AUTH STARTER · PASSKEY (WEBAUTHN)
Passkey (WebAuthn)
Face ID, Touch ID, hardware keys. Once a user adds one, they never type a password again on that device.
Passkeys are WebAuthn under the hood. The user registers a credential (their device's biometric or a YubiKey), and from then on "sign in with passkey" is a single Face ID prompt. No password to type, no email to wait for.
Turn it on
// src/auth.config.ts
plugins: {
passkey: { enabled: true },
},The server-side rpID and origin come from authServerConfig.passkey — derived from BETTER_AUTH_URL. You don't usually touch them.
Register a passkey (after sign-in)
await authClient.passkey.addPasskey();
// Browser prompts the user — Face ID, Touch ID, security key, etc.Sign in with passkey
await authClient.signIn.passkey();rpID must match the hostname exactly
rpID = new URL(BETTER_AUTH_URL).hostname. If your prod URL is https://app.yourdomain.com, rpID is app.yourdomain.com. Passkeys registered against one rpID are USELESS at another — including subdomains. Choose your canonical domain BEFORE launch.
Passkeys do NOT work on http (except localhost)
WebAuthn requires HTTPS. The browser will silently fail to register a passkey on an http:// staging URL. localhost is the only HTTP exception. Use HTTPS in any test environment users will touch.
Account recovery is on you
If a user loses all their devices, their passkey is gone. Always offer at least one fallback method (email OTP, password) so users aren't locked out forever. The dashboard component passkey-manage.tsx lets them register multiple passkeys — encourage that.
The DB table
Enabling passkey adds a passkey table to the schema (credential id, public key, counter, transports). Run db:push (dev) or generate + migrate (prod) after toggling on.