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

Laravel Webauthn Laravel Package

rawilk/laravel-webauthn

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require rawilk/laravel-webauthn
    php artisan vendor:publish --tag="webauthn-migrations"
    php artisan vendor:publish --tag="webauthn-config"
    php artisan migrate
    
    • Publishes migrations (creates webauthn_credentials table) and config file.
  2. First Use Case:

    • Register a new credential (e.g., security key) for a user:
      use Rawilk\Webauthn\Webauthn;
      
      $user = auth()->user();
      $webauthn = new Webauthn($user);
      $options = $webauthn->createRegistrationOptions();
      return view('webauthn.register', compact('options'));
      
    • Verify registration response (after user completes challenge):
      $result = $webauthn->verifyRegistrationResponse($request->all());
      if ($result->isSuccess()) {
          // Credential registered successfully
      }
      
  3. Key Files to Review:

    • config/laravel-webauthn.php: Configure RP (Relying Party) ID, origin, and security policies.
    • resources/views/webauthn/: Default Blade views (extend/modify as needed).
    • app/Models/WebauthnCredential.php: Model for storing credentials (extend for custom logic).

Implementation Patterns

Core Workflows

1. Credential Registration Flow

  • Step 1: Generate challenge options (server-side):
    $webauthn = new Webauthn($user);
    $options = $webauthn->createRegistrationOptions();
    
    • Returns WebauthnRegistrationOptions with challenge, rp, user, and pubKeyCredParams.
  • Step 2: Send to frontend (via Blade/JS):
    @webauthnRegister($options)
    
    • Renders a form with publicKey options for the WebAuthn API.
  • Step 3: Verify response (after user completes auth):
    $result = $webauthn->verifyRegistrationResponse($request->all());
    if ($result->isSuccess()) {
        $credential = $result->getCredential();
        $user->webauthnCredentials()->save($credential);
    }
    

2. Authentication Flow

  • Step 1: Generate assertion options:
    $webauthn = new Webauthn($user);
    $options = $webauthn->createAssertionOptions();
    
  • Step 2: Send to frontend:
    @webauthnAuthenticate($options)
    
  • Step 3: Verify assertion:
    $result = $webauthn->verifyAssertionResponse($request->all());
    if ($result->isSuccess()) {
        // Authenticate user
        auth()->login($user);
    }
    

3. Credential Management

  • List user credentials:
    $credentials = $user->webauthnCredentials;
    
  • Delete a credential:
    $credential = $user->webauthnCredentials()->find($id);
    $credential->delete();
    

Integration Tips

Laravel Authentication Integration

  • Extend LoginController:

    public function authenticate(Request $request) {
        $user = User::find($request->user_id);
        $webauthn = new Webauthn($user);
        $result = $webauthn->verifyAssertionResponse($request->all());
    
        if ($result->isSuccess()) {
            auth()->login($user);
            return redirect()->intended('/dashboard');
        }
        return back()->withErrors(['auth' => 'Invalid credential']);
    }
    
  • Add WebAuthn as a guard:

    // config/auth.php
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
            'webauthn' => true, // Custom flag to enable WebAuthn checks
        ],
    ];
    

Frontend Integration

  • Use the @webauthnRegister/@webauthnAuthenticate directives in Blade:

    @webauthnRegister($options)
    <script>
        document.querySelector('webauthn-register-form').addEventListener('submit', async (e) => {
            e.preventDefault();
            const result = await navigator.credentials.create({ publicKey: @json($options) });
            // Submit result to server
        });
    </script>
    
  • Customize the WebAuthn UI:

    • Override default views in resources/views/webauthn/.
    • Extend the WebauthnAssets helper to include custom CSS/JS:
      WebauthnAssets::addJs('custom-webauthn.js');
      

Testing

  • Unit Test Verification:

    public function test_registration_verification() {
        $user = User::factory()->create();
        $webauthn = new Webauthn($user);
        $options = $webauthn->createRegistrationOptions();
    
        // Mock a valid response
        $response = [
            'id' => 'test-credential-id',
            'rawId' => 'base64-encoded-id',
            'type' => 'public-key',
            'response' => [
                'attestationObject' => 'base64-attestation',
                'clientDataJSON' => 'base64-client-data',
                'transports' => ['usb', 'ble'],
            ],
        ];
    
        $result = $webauthn->verifyRegistrationResponse($response);
        $this->assertTrue($result->isSuccess());
    }
    
  • Browser Testing:

    • Use tools like WebAuthn.io to simulate WebAuthn responses.
    • Test with real hardware keys (YubiKey, Solo) or emulators (e.g., WebAuthn Test Tool).

Gotchas and Tips

Pitfalls

  1. CORS and Origin Configuration:

    • Ensure webauthn.rp.origin in the config matches your exact production domain (e.g., https://app.yourdomain.com).
    • Misconfiguration can cause NotAllowedError during registration/authentication.
    • Fix: Verify the origin in config/laravel-webauthn.php and ensure your server’s Host header matches.
  2. CSRF and WebAuthn:

    • WebAuthn challenges are not protected by CSRF tokens by default. Use webauthn.challenge_expiration to limit challenge validity (default: 60 seconds).
    • Tip: Combine with Laravel’s CSRF middleware for other form submissions.
  3. Credential ID Collisions:

    • If users register the same credential (e.g., same YubiKey) across multiple accounts, the id field may collide.
    • Solution: Store the rawId (base64-encoded credential ID) and use it for deduplication:
      $exists = WebauthnCredential::where('raw_id', $response['rawId'])->exists();
      
  4. Browser/Device Compatibility:

    • WebAuthn requires HTTPS (or localhost for development).
    • Some browsers (e.g., Safari) have limited support for platform authenticators (Touch ID/Face ID).
    • Tip: Test with Can I use WebAuthn? and provide fallbacks (e.g., TOTP).
  5. Database Schema Assumptions:

    • The package assumes a webauthn_credentials table with specific fields (id, user_id, credential_id, public_key, raw_id, transports, counter).
    • Customization: Extend the WebauthnCredential model if you need additional fields (e.g., name, last_used_at).

Debugging Tips

  1. Enable Verbose Logging:

    • Set webauthn.debug to true in the config to log challenges/responses.
    • Check Laravel logs for errors like:
      WebAuthnError: Invalid client data JSON
      
  2. Validate Client Data:

    • The clientDataJSON in the response must match the challenge you sent. Use:
      $webauthn->verifyRegistrationResponse($request->all())->getErrors();
      
    • Common issues:
      • Challenge mismatch: Ensure the challenge is sent to the client and returned unchanged.
      • Origin mismatch: Verify origin in clientDataJSON matches your config.
  3. Handle Attestation:

    • The package supports none, direct, and indirect attestation. If using none, ensure your RP ID is set correctly:
      config(['webauthn.rp.id' => 'yourdomain.com']);
      
  4. Counter Management:

    • The counter field prevents replay attacks. If a credential’s counter is lower than the stored value
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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime