Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Webauthn Laravel Package

laragear/webauthn

Laravel package to authenticate users with WebAuthn passkeys (biometrics, device keys). Provides request validation and login flow with attestation/assertion support, compatible with Octane. Note: superseded by laravel/passkeys and unmaintained.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require laragear/webauthn
    php artisan webauthn:install
    php artisan migrate
    
  2. Configure Auth: Update config/auth.php:

    'providers' => [
        'users' => [
            'driver' => 'eloquent-webauthn',
            'model' => App\Models\User::class,
            'password_fallback' => true,
        ],
    ]
    
  3. Add Trait/Contract to User Model:

    use Laragear\WebAuthn\Contracts\WebAuthnAuthenticatable;
    use Laragear\WebAuthn\WebAuthnAuthentication;
    
    class User implements WebAuthnAuthenticatable
    {
        use WebAuthnAuthentication;
    }
    
  4. Register Routes (in web.php):

    use Laragear\WebAuthn\Http\Routes;
    
    Route::middleware('web')->group(function () {
        Routes::register()->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class);
    });
    
  5. First Use Case:

    • Registration: Call /webauthn/register/options to get attestation options, then POST to /webauthn/register with the authenticator response.
    • Login: Call /webauthn/login/options to get assertion options, then POST to /webauthn/login with the authenticator response.

Implementation Patterns

Workflows

Attestation (Registration)

  1. Generate Options:

    public function registerOptions(AttestationRequest $request)
    {
        return $request->toCreate();
    }
    
    • Use fastRegistration() or secureRegistration() to control user verification.
    • Use userless() for resident keys (one-touch login).
    • Use allowDuplicates() to bypass existing credential checks.
  2. Handle Response:

    public function register(AttestedRequest $request)
    {
        $request->save(); // Saves to `webauthn_credentials` table
        return response()->json(['message' => 'Passkey registered!']);
    }
    
    • Customize saved data via callback:
      $request->save(fn ($credential) => $credential->alias = $request->alias);
      

Assertion (Login)

  1. Generate Options:

    public function loginOptions(AssertionRequest $request)
    {
        return $request->toAssert();
    }
    
  2. Handle Response:

    public function login(AssertedRequest $request)
    {
        $user = $request->login(); // Automatically validates and logs in
        return response()->json(['user' => $user]);
    }
    

Custom Controllers

Override default controllers in routes/web.php:

Routes::register(
    attest: 'custom/register',
    assert: 'custom/login'
);

Integration Tips

  • Frontend Integration: Use @laragear/webpass for JavaScript:
    const { success } = await Webpass.attest('/webauthn/register/options', '/webauthn/register');
    
  • Fallback to Passwords: Ensure password_fallback: true in auth.php for hybrid auth.
  • Testing: Use WebAuthnTestCase for unit/feature tests:
    use Laragear\WebAuthn\Testing\WebAuthnTestCase;
    
    class WebAuthnTest extends WebAuthnTestCase { ... }
    

Gotchas and Tips

Pitfalls

  1. CSRF/XSRF:

    • WebAuthn routes are CSRF-exempt by default. If using @laragear/webpass, manually add tokens for non-exempt routes.
    • Fix: Explicitly exclude VerifyCsrfToken:
      Routes::register()->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class);
      
  2. User Authentication:

    • AttestationRequest/AttestedRequest require authenticated users. For guest registration:
      • Temporarily log in the user:
        Auth::login($user);
        $request->toCreate();
        Auth::logout();
        
      • Or use WebAuthn::attest()/WebAuthn::assert() manually:
        $options = WebAuthn::attest($user);
        $credential = WebAuthn::verify($response, $options);
        
  3. Resident Keys:

    • userless() requires user verification on assertion. Test with biometric/PIN authenticators.
  4. Duplicate Credentials:

    • allowDuplicates() bypasses exclusion checks but may cause authenticator confusion.
  5. Key Storage:

    • Public keys are stored in webauthn_credentials. Ensure the table has:
      Schema::create('webauthn_credentials', function (Blueprint $table) {
          $table->id();
          $table->foreignId('user_id')->constrained()->cascadeOnDelete();
          $table->json('public_key_credential');
          $table->json('transports')->nullable();
          $table->json('metadata')->nullable();
          $table->timestamps();
      });
      

Debugging

  • Validation Errors: Check AttestedRequest/AssertedRequest for validation exceptions. Log raw responses:
    \Log::debug('WebAuthn Response:', $request->all());
    
  • OpenSSL/Sodium:
    • Ensure ext-openssl is enabled.
    • For EdDSA (25519), install ext-sodium or paragonie/sodium_compat.

Extension Points

  1. Custom Credential Model: Extend Laragear\WebAuthn\Models\WebAuthnCredential:

    class CustomCredential extends WebAuthnCredential { ... }
    

    Update config/webauthn.php:

    'model' => App\Models\CustomCredential::class,
    
  2. Custom Attestation/Assertion Logic: Override WebAuthnAuthentication trait methods:

    public function getWebAuthnCredentials()
    {
        return $this->credentials()->where('active', true);
    }
    
  3. Event Listeners: Listen for credential events:

    WebAuthnCredentialCreated::dispatch($credential);
    

Configuration Quirks

  • RP ID: Ensure config/webauthn.php has correct rp_id (e.g., yourdomain.com).
  • Challenge Timeout: Default is 60 seconds. Adjust in config/webauthn.php:
    'challenge_timeout' => 300, // 5 minutes
    
  • Allowed Credential IDs: Customize exclusion logic in getExcludedCredentialIds():
    public function getExcludedCredentialIds()
    {
        return $this->credentials()->pluck('id')->toArray();
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky