laravel/passkeys
Laravel Passkeys adds passwordless WebAuthn authentication to Laravel apps, with built-in routes for passkey login, confirmation, and management, configurable relying party settings, custom model support, and a matching @laravel/passkeys JavaScript client.
@laravel/passkeys npm client. That converts "passwordless" from a multi-sprint security project into a scoped increment you can put behind a flag.Passkeys.verify() above the password form. One-line guest-page change, measurable lift on returning-user login.GET/POST /passkeys/confirm plus the documented GenerateVerificationOptions + VerifyPasskey pattern with an authenticated user lets you require a fresh passkey assertion before password change, payout, key rotation, or admin impersonation — without logging the user in again. For most products this replaces SMS OTP (weak, costly per-message, SIM-swap exposed) and is the strongest single justification for adoption.PasskeyRegistered / PasskeyVerified / PasskeyDeleted and track: enrollment rate among active users, passkey-login share, reset-ticket volume per 1k MAU, and ATO incidents. Those four numbers are the business case and the go/no-go for phase three.Passkeys::authorizeLoginUsing() gives you the compliance-critical gate — block suspended or banned accounts after a cryptographically valid assertion, which is exactly the check auditors ask about.management_middleware defaults to password.confirm on passkey add/delete, which is the right default for admin tooling. For internal dashboards and back-office apps, passkeys are arguably a stronger ROI than for consumer apps — smaller user base, higher blast radius per compromise, no recovery-funnel anxiety.Consider adoption when all of these hold:
guard => 'web' is the default and the package assumes it; API-token or SPA-with-separate-auth-service architectures need more work than the README implies.@laravel/passkeys, prompt for a device name, and build the credential list/revoke UI.PasskeyAuthenticatable trait resolves display name as name → email → auth ID and username as email → auth ID. If you display handles, employee IDs, or tenant-scoped emails, budget an afternoon to override getPasskeyDisplayName() / getPasskeyUsername() — this string is what the OS account picker shows the user six months later with three devices registered.web, including GET /user/passkeys/options and DELETE /user/passkeys/{passkey}. If you own /user/*, audit with php artisan route:list. Passkeys::ignoreRoutes() exists if you need to take over routing.Look elsewhere when:
ASAuthorizationPlatformPublicKeyCredentialProvider and Android Credential Manager integration are yours to build against the same endpoints — feasible, but it's a project, not a dependency.laravel namespace — which materially lowers abandonment risk, but doesn't create a support contract).user_handle_secret defaults to APP_KEY, so rotating APP_KEY silently invalidates every existing credential's user handle. Set PASSKEYS_USER_HANDLE_SECRET explicitly and treat it as rotation-sensitive — that's a config decision with a multi-year consequence.authenticatorSelection override (platform-only, resident key required) covers the common cases; anything more exotic means extending the actions and owning that code.For executives — the one-paragraph version: Passkeys replace passwords with Face ID, Touch ID, or a security key. This is a small, first-party Laravel package that lets us ship passkey sign-in in weeks rather than a quarter, and we can do it in stages so nothing about the current login flow changes until we choose to flip it. The upside is threefold: fewer account takeovers (passkeys are phishing-resistant — there's no secret to steal), fewer password-reset tickets (a real, measurable support cost), and a straight answer to the "do you support FIDO2?" question that now appears in enterprise security reviews. We recommend starting with enrollment in account settings — low risk, fully reversible, and it produces the data we need to decide whether to make passkeys a first-class login method.
For engineering — the assessment:
composer require, publish migrations, add PasskeyAuthenticatable + PasskeyUser to User, done. Seven routes register under web; three events fire (PasskeyRegistered, PasskeyVerified, PasskeyDeleted) so you can hook analytics and audit logging without forking.password.confirm by default). That locking change alone justifies not hand-rolling this.authorizeLoginUsing() for banned/suspended gating; GenerateVerificationOptions + VerifyPasskey for step-up auth without re-login; bindable actions (e.g. force platform authenticators + resident keys for true passkey UX); four response contracts; custom Passkey model; Passkeys::ignoreRoutes().PASSKEYS_USER_HANDLE_SECRET config.laravel namespace is the main reason the abandonment risk is tolerable.How can I help you explore Laravel packages today?