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 Passkeys Laravel Package

spatie/laravel-passkeys

Add passkey (WebAuthn) login to your Laravel app. Provides a Livewire component to create and manage passkeys and a Blade component to authenticate users without passwords, using platform authenticators like iCloud Keychain or 1Password.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-passkeys
    

    Ensure Livewire is installed (composer require livewire/livewire).

  2. Publish Config:

    php artisan vendor:publish --provider="Spatie\Passkeys\PasskeysServiceProvider"
    

    Configure config/passkeys.php (e.g., relying_party_name, allowed_origins).

  3. Run Migrations:

    php artisan migrate
    

    Creates passkeys table for storing credentials.

  4. First Use Case:

    • Registration: Use the Livewire component in your registration form:
      <x-passkeys::register />
      
    • Authentication: Use the Blade component in your login form:
      <x-passkeys::authenticate />
      

Implementation Patterns

Core Workflows

1. Passkey Registration

  • Livewire Integration:
    <livewire:passkeys.register
        :user="$user"
        :options="['challenge' => $challenge, 'rp' => ['name' => config('passkeys.relying_party_name')]]"
    />
    
  • Customize Options:
    use Spatie\Passkeys\GeneratePasskeyRegisterOptions;
    
    $options = GeneratePasskeyRegisterOptions::create()
        ->withAuthenticatorSelection([
            'authenticatorAttachment' => 'platform',
            'requireResidentKey' => true,
        ]);
    

2. Passkey Authentication

  • Blade Component:
    <x-passkeys::authenticate
        :user="$user"
        :options="['challenge' => $challenge, 'rpId' => config('passkeys.relying_party_id')]"
    />
    
  • Manual Authentication (e.g., in a controller):
    use Spatie\Passkeys\AuthenticateWithPasskey;
    
    $authenticator = AuthenticateWithPasskey::create($user)
        ->withChallenge($challenge)
        ->withRemember($request->has('remember'))
        ->authenticate();
    

3. Passkey Management

  • List User Passkeys:
    $passkeys = $user->passkeys()->get();
    
  • Delete a Passkey:
    $user->passkeys()->where('id', $passkeyId)->delete();
    

4. Event Handling

  • Listen for passkey registration events:
    use Spatie\Passkeys\Events\PasskeyRegistered;
    
    PasskeyRegistered::subscribe(function (PasskeyRegistered $event) {
        // Log or notify when a passkey is registered
    });
    

Integration Tips

Livewire + Inertia

  • Livewire: Use the provided Livewire components directly in Blade views.
  • Inertia: Pass the passkeys array to your Inertia props:
    return Inertia::render('Auth/Register', [
        'passkeys' => $user->passkeys()->get()->toArray(),
    ]);
    

Multi-Factor Authentication (MFA)

  • Combine with Laravel’s built-in MustVerifyEmail or third-party MFA packages:
    use Spatie\Passkeys\HasPasskeys;
    
    class User extends Authenticatable
    {
        use HasPasskeys, MustVerifyEmail;
    }
    

Custom UI

  • Extend the Blade components:
    <x-passkeys::authenticate>
        @slot('before')
            <p>Use your passkey for secure login.</p>
        @endslot
    </x-passkeys::authenticate>
    

Gotchas and Tips

Pitfalls

  1. WebAuthn Library Version Conflicts:

    • Ensure web-auth/webauthn-lib is compatible (v5.3+ requires adjustments for CredentialRecord).
    • Fix: Update the package or patch the Passkey model’s data accessor:
      public function getDataAttribute(): array
      {
          return $this->attributes['data'] ?? [];
      }
      
  2. Relying Party ID (RP ID):

    • The RP ID must match across registration/authentication. Use config('passkeys.relying_party_id').
    • Debug: Log the RP ID during registration/authentication to verify consistency.
  3. Challenge Persistence:

    • Challenges must be stored and reused for the same authentication flow. Use sessions or database:
      session(['passkey_challenge' => $challenge]);
      
  4. Livewire Component State:

    • Avoid resetting Livewire components mid-flow (e.g., during challenge validation). Use wire:ignore or persist state.
  5. Allowed Origins:

    • Misconfigured allowed_origins in config/passkeys.php can break passkey registration/authentication.
    • Test: Use http://localhost and your production domain during development.

Debugging Tips

  1. Enable WebAuthn Debugging:

    • Set WEB_AUTHN_DEBUG in .env to log WebAuthn errors:
      WEB_AUTHN_DEBUG=true
      
    • Check logs for webauthn-lib exceptions.
  2. Validate Credential Responses:

    • Use the webauthn-lib validator directly:
      use WebAuthn\Validation;
      
      $validator = new Validation();
      $result = $validator->validatePresence($credential, $options);
      
  3. Inspect Passkey Data:

    • Dump passkey attributes for debugging:
      dd($user->passkeys()->first()->attributes);
      

Extension Points

  1. Custom Passkey Model:

    • Extend Spatie\Passkeys\Models\Passkey to add fields (e.g., device_name):
      class CustomPasskey extends Passkey
      {
          protected $casts = [
              'device_name' => 'string',
          ];
      }
      
  2. Override Default Options:

    • Create a macro for GeneratePasskeyRegisterOptions:
      GeneratePasskeyRegisterOptions::macro('withCustomRP', function () {
          return $this->withRelyingParty([
              'name' => 'Custom App',
              'id' => 'custom.app',
          ]);
      });
      
  3. Custom Events:

    • Extend PasskeyRegistered or create new events (e.g., PasskeyDeleted):
      event(new CustomPasskeyEvent($user, $passkey));
      
  4. Fallback Authentication:

    • Combine with traditional auth (e.g., email/password) using middleware:
      public function handle($request, Closure $next)
      {
          if ($request->has('passkey') && !$request->user()->hasPasskeys()) {
              return redirect()->route('login');
          }
          return $next($request);
      }
      

Configuration Quirks

  1. Relying Party Name:

    • Must match the domain used in registration/authentication (e.g., config('passkeys.relying_party_name') should be YourApp for your-app.com).
  2. Allowed Origins:

    • Include all domains where passkeys will be used (e.g., localhost, app.yourdomain.com):
      'allowed_origins' => [
          'http://localhost:3000',
          'https://app.yourdomain.com',
      ],
      
  3. Challenge Generation:

    • Use Laravel’s Str::random(32) for challenges, but ensure uniqueness per session:
      $challenge = Str::random(32);
      session(['passkey_challenge' => $challenge]);
      
  4. User Model Binding:

    • Ensure the HasPasskeys trait is used in your User model:
      use Spatie\Passkeys\HasPasskeys;
      
      class User extends Authenticatable
      {
          use HasPasskeys;
      }
      

Performance Considerations

  1. Database Indexes:

    • Add indexes to passkeys table for user_id and credential_id:
      Schema::table('passkeys', function (Blueprint $table) {
          $table->index('user_id');
          $table->index('credential_id');
      });
      
  2. Caching Challenges:

    • Cache challenges in Redis for high-traffic apps:
      Cache::put("passkey_challenge_{$user->id}", $challenge, now()->addMinutes(5));
      
  3. Batch Operations:

    • Avoid loading all passkeys for users with many credentials. Use cursors or pagination:
      $passkeys = $user->passkeys()->paginate(10);
      
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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony