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

Passkey Laravel Package

moox/passkey

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation Run the package installer:

    composer require moox/passkey
    php artisan mooxpasskey:install
    

    This publishes migrations, config, and sets up the necessary tables (passkey_credentials, passkey_users).

  2. Configure Authentication Update your config/auth.php to use the passkey guard (if not already configured):

    'guards' => [
        'web' => [
            'driver' => 'passkey',
            'provider' => 'users',
        ],
    ],
    
  3. First Endpoint Use the built-in PasskeyController to handle registration and authentication:

    use Moox\Passkey\Http\Controllers\PasskeyController;
    
    Route::get('/register-passkey', [PasskeyController::class, 'showRegistrationForm']);
    Route::post('/register-passkey', [PasskeyController::class, 'register']);
    Route::post('/login-passkey', [PasskeyController::class, 'authenticate']);
    
  4. Test with a User Register a passkey for a test user via the /register-passkey endpoint, then authenticate using the generated credential.


Implementation Patterns

Core Workflows

  1. Passkey Registration

    • Trigger the registration flow via PasskeyController::showRegistrationForm().
    • Handle the response with PasskeyController::register(), which:
      • Generates a challenge.
      • Stores the credential in passkey_credentials.
      • Returns a JSON response with the public key and challenge for client-side processing.
    • Client-side: Use the Web Authentication API to create a credential and send it back to Laravel.
  2. Passkey Authentication

    • Use PasskeyController::authenticate() to verify a credential.
    • The controller validates the credential against stored data and logs the user in if valid.
  3. Fallback Authentication

    • Extend the PasskeyGuard to support traditional password-based fallback:
      use Moox\Passkey\Guard;
      
      class CustomGuard extends Guard {
          public function authenticateWithPassword($credentials) {
              // Custom logic for password fallback
          }
      }
      

Integration Tips

  • Laravel Fortify/Passport Replace or extend Fortify’s login logic to use PasskeyController for passkey-based auth. Example:

    // In a custom Fortify provider
    public function createLoginResponse(Request $request) {
        if ($request->has('passkey')) {
            return PasskeyController::authenticate($request);
        }
        return parent::createLoginResponse($request);
    }
    
  • Multi-Factor Authentication (MFA) Combine with Laravel’s built-in MFA:

    use Moox\Passkey\Facades\Passkey;
    
    public function enablePasskeyMFA(User $user) {
        $credential = Passkey::register($user);
        $user->mfa_secret = $credential->secret; // Store for MFA
        $user->save();
    }
    
  • Customizing Credential Storage Override the PasskeyCredential model to add custom fields (e.g., device_name):

    namespace App\Models;
    
    use Moox\Passkey\Models\PasskeyCredential as BaseCredential;
    
    class PasskeyCredential extends BaseCredential {
        protected $casts = [
            'device_name' => 'string',
        ];
    }
    
  • Webhook Events Listen for passkey events (e.g., passkey.registered):

    use Moox\Passkey\Events\PasskeyRegistered;
    
    PasskeyRegistered::listen(function (PasskeyRegistered $event) {
        // Send email/notification
    });
    

Gotchas and Tips

Pitfalls

  1. Challenge Expiry

    • Passkey challenges expire after 60 seconds by default (configurable in config/passkey.php).
    • Fix: Ensure client-side credential creation completes within this window or regenerate the challenge.
  2. Browser/Device Compatibility

    • Passkeys require modern browsers (Chrome 89+, Edge 89+, Safari 15.4+).
    • Tip: Provide a fallback UI for unsupported devices:
      if (!Passkey::isSupported()) {
          return view('auth.fallback');
      }
      
  3. Credential ID Collisions

    • If a user registers multiple passkeys with the same id (e.g., from different devices), the second registration may fail.
    • Solution: Use a UUID for id or validate uniqueness in the PasskeyCredential model:
      public static function boot() {
          static::creating(function ($model) {
              $model->id = Str::uuid()->toString();
          });
      }
      
  4. Migration Conflicts

    • If you manually publish migrations, ensure the passkey_credentials table schema matches the package’s expectations (e.g., credential_id as primary key).
    • Debug: Run php artisan vendor:publish --tag="passkey-migrations" and compare with the package’s default migration.
  5. CORS Issues

    • Passkey registration/authentication requires CORS headers for the credential creation/authentication steps.
    • Fix: Add to your CORS config:
      'paths' => ['api/passkey/*', 'sanctum/csrf-cookie'],
      'allowed_methods' => ['*'],
      'allowed_origins' => ['https://yourdomain.com'],
      'allowed_headers' => ['*'],
      

Debugging Tips

  • Enable Logging Add to config/passkey.php:

    'debug' => env('PASSKEY_DEBUG', false),
    

    Logs will appear in storage/logs/laravel.log.

  • Inspect Credentials Dump stored credentials for debugging:

    use Moox\Passkey\Models\PasskeyCredential;
    
    PasskeyCredential::where('user_id', auth()->id())->dd();
    
  • Test with Mock Data Use Laravel’s Passport or Sanctum mock guards to test passkey flows without real credentials:

    Passkey::shouldReceive('verifyCredential')->andReturn(true);
    

Extension Points

  1. Custom Credential Verification Override the verifyCredential method in a custom PasskeyService:

    namespace App\Services;
    
    use Moox\Passkey\Services\PasskeyService as BaseService;
    
    class CustomPasskeyService extends BaseService {
        public function verifyCredential($credentialId, $publicKey, $signature, $challenge) {
            // Custom logic (e.g., rate limiting, additional checks)
            return parent::verifyCredential($credentialId, $publicKey, $signature, $challenge);
        }
    }
    

    Bind it in AppServiceProvider:

    $this->app->bind(
        \Moox\Passkey\Contracts\PasskeyService::class,
        App\Services\CustomPasskeyService::class
    );
    
  2. Passkey Metadata Extend the PasskeyCredential model to store metadata (e.g., device_type, last_used_at):

    use Illuminate\Database\Eloquent\Casts\Attribute;
    
    protected function lastUsed(): Attribute {
        return Attribute::make(
            get: fn () => $this->updated_at->diffForHumans(),
        );
    }
    
  3. Rate Limiting Add rate limiting to the PasskeyController:

    use Illuminate\Cache\RateLimiting\Limit;
    
    Route::middleware(['throttle:60,1'])->group(function () {
        Route::post('/login-passkey', [PasskeyController::class, 'authenticate']);
    });
    
  4. Passkey Backup Codes Implement backup codes for passkey recovery:

    use Moox\Passkey\Facades\Passkey;
    
    $backupCode = Passkey::generateBackupCode();
    $user->backup_code = $backupCode;
    $user->save();
    
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope