asbiin/laravel-webauthn
asbiin/laravel-webauthn brings passwordless WebAuthn authentication to Laravel. Let users register security keys, Touch ID, Face ID, or Windows Hello and sign in without passwords using simple routes, middleware, and configurable user models.
composer require asbiin/laravel-webauthnphp artisan vendor:publish --tag=webauthn-migrations && php artisan migrate (creates the webauthn_keys table).php artisan vendor:publish --tag=webauthn-config — this is the first file to open.WebauthnAuthenticatable trait to your User model (it provides the webAuthnCredentials() relation).@simplewebauthn/browser and feed the JSON options from your endpoints into startRegistration() / startAuthentication().Where to look first: config/webauthn.php (routes, rp_id, origins, middleware), the Webauthn facade (LaravelWebauthn\Facades\Webauthn), and the default WebauthnRegisterController / WebauthnLoginController shipped by the package.
First use case: add WebAuthn as a second factor behind an existing password login. Hit the built-in /webauthn/register flow to enroll a key, then gate sensitive routes behind the assertion flow. Only reach for custom controllers once the default flow works end to end.
GET that returns Webauthn::generateAttestationOptions($user) as JSON, and a POST that calls Webauthn::validateAttestation($user, $request->input('response')) and persists the returned CredentialRecord. The package's default controller already handles persistence via the trait relation.GET returns Webauthn::generateAssertionOptions($user); POST calls Webauthn::validateAssertion($user, $request->input('response')). On success, Auth::login($user) and session()->regenerate(). Reuse the same assertion flow for "confirm before deleting account" style step-up screens.$user->webAuthnCredentials; deleting a row is a normal Eloquent delete.--tag=webauthn-views, or @json($options) into your own. Remember to base64url-decode challenge and user.id before passing them to startRegistration / startAuthentication.validateAttestation() / validateAssertion() as a CredentialRecord value object and read it only through getters (see Gotchas) — this is the main behavioural change custom integrations need to absorb.validateAttestation() / validateAssertion() now return a CredentialRecord (webauthn-lib 5.3) instead of the deprecated PublicKeyCredentialSource. Property access becomes method calls: ->publicKeyCredentialId → ->getPublicKeyCredentialId(), ->userHandle → ->getUserHandle(), ->credentialPublicKey → ->getPublicKey(), ->counter → ->getCounter(), ->transports → ->getTransports(), ->aaguid → ->getAaguid(). Apps using only the built-in controllers will upgrade without touching code; only custom code that inspected the returned object needs editing. Upgrade path: composer update, then grep for PublicKeyCredentialSource and for -> access on validate results. DB schema and JS are unchanged.localhost). rp_id and origin values in config/webauthn.php must match the browser origin exactly; a mismatch surfaces as an opaque DOMException in JS, not a PHP error.Webauthn facade (or bind a fake) and assert on your controller's redirect/session behaviour; use the package's own test suite as a template for stubbing validate calls.last_used_at column and touch it in a listener around the assert flow.How can I help you explore Laravel packages today?