Passkeys let users sign in with their device's biometrics (Face ID, Touch ID, Windows Hello) or a hardware security key instead of a password. They are passwordless and phishing-resistant by design.
Passkeys are disabled by default. Because they add a passkey database table, enabling them is a provisioning decision in two parts — not a single env flag.
Flip the committed constant — the single source of truth shared by schema generation (config.ts) and the runtime (auth.ts):
export const ENABLE_PASSKEY = true;
Then regenerate the schema and apply the migration:
pnpm --filter @kit/better-auth schema:generate pnpm --filter @kit/database drizzle:generate pnpm --filter @kit/database drizzle:migrate
While ENABLE_PASSKEY is false, the passkey plugin is not registered server-side, so the /passkey/* endpoints don't exist — disabling is a real boundary, not just a hidden UI.
NEXT_PUBLIC_AUTH_PASSKEY=true
With both set:
NEXT_PUBLIC_AUTH_PASSKEY=true only controls the UI. Setting it without ENABLE_PASSKEY=true (and the migration applied) renders a passkey button whose endpoints don't exist. Always provision first.
A passkey is bound to an existing account, so users register one after they already have an account:
NEXT_PUBLIC_SITE_URL. In development this is localhost; in production it must be your real domain (e.g. app.example.com). A mismatch causes the browser to reject the passkey.passkey table, provisioned by setting ENABLE_PASSKEY and regenerating the schema. See Enable Passkeys for the full sequence.import { authClient } from '@kit/better-auth/client';
// While signed in: register a passkey
await authClient.passkey.addPasskey({ name: 'MacBook Touch ID' });
// List registered passkeys
const { data: passkeys } = await authClient.passkey.listUserPasskeys();
// Remove a passkey
await authClient.passkey.deletePasskey({ id: passkeyId });
// On a later visit: sign in with a passkey
await authClient.signIn.passkey();
The kit also ships hooks under @kit/auth/hooks: use-add-passkey, use-list-passkeys, use-delete-passkey, and use-sign-in-with-passkey.
Good for:
Consider alternatives when: