lbuchs/webauthn
PHP WebAuthn (FIDO2) library for passwordless login. Generate and verify registration and authentication challenges, validate attestation and assertions, and integrate with Laravel or any PHP app for secure passkeys and hardware security keys.
Start by installing the package via Composer: composer require lbuchs/webauthn. Since it’s designed for framework integration (especially Laravel), begin by initializing the RelyingParty class with your app’s domain (rpId), name, and origin (e.g., https://yourapp.test). You’ll primarily interact with two core flows: registration and authentication.
navigator.credentials.create() for registration and navigator.credentials.get() for login—see the library’s examples for starter JS snippets.AuthController endpoints: /webauthn/register/start, /webauthn/register/finish, and /webauthn/login/start, /webauthn/login/finish.Look first at the examples/ directory in the repo (even if "unknown", examples are standard in WebAuthn libs) for Laravel-style workflows. The RelyingParty constructor is your entry point—review its config options: rpId, rpName, origin, and attestationTypes.
Challenge lifecycle: Generate a unique, cryptographically secure challenge per session/user. Store it (e.g., in session or cache) before sending to client. Use RelyingParty::startRegistration() / startAuthentication() for this.
Credential storage: Save returned credentialId, publicKey, attestationType, transports, and signInCount in your users or dedicated webauthn_credentials table. The credentialId is base64-encoded binary—store as BINARY/VARBINARY or base64 string.
Stateless RP ID handling: In Laravel, set rpId to your app’s host only (e.g., example.com, not sub.example.com) to support subdomain logins safely. Use config('app.url') to derive origin dynamically.
User verification (UV) vs. user presence (UP): For passwordless login, enable userVerification = 'required'. For MFA, preferred or discouraged is fine. Configure via startAuthentication(['userVerification' => 'required']).
Laravel-specific pattern: Wrap the library in a dedicated service (e.g., WebAuthnService) that handles DB persistence and integrates with your Authenticatable model. Example method: public function registerCredential($user, $response).
Cross-platform vs. platform: Let users choose authenticator type by setting authenticatorSelection in config:
$startResult = $rp->startRegistration($user, [
'authenticatorSelection' => [
'residentKey' => 'preferred',
'userVerification' => 'preferred'
]
]);
validationError: 'ChallengeMismatch' occurs, ensure challenges aren’t reused, regenerated, or stale. Always use fresh challenges per ceremony. Laravel session flash() can help avoid persistence mistakes.app.example.com, rpId must be example.com or app.example.com. Defaulting to the full URL (e.g., https://app.example.com) causes subtle failures.post_max_size and upload_max_filesize in php.ini, and ensure your CORS config allows Content-Type: application/json.userHandle (unique per user) must be binary-safe. In Laravel, use Str::random(16) and store as binary field. Never use email or username directly.none for best compatibility. Only enable direct or indirect attestation if you need authenticator attestation (e.g., for compliance).challenge + clientResponse.origin + clientResponse.challenge during development. Use webauthn/debug middleware or Laravel Telescope to inspect flow state.AttestationValidator, AssertionValidator). Override them via dependency injection or extend RelyingParty to customize security policies (e.g., enforce AAGUID whitelist for corporate keys).How can I help you explore Laravel packages today?