Passkeys
Use WebAuthn passkeys for primary sign-in or as a user-verified second factor.
Overview
Passkeys can sign a user in directly or complete an MFA challenge. Both modes use the same credential storage and verification service.
Configure WebAuthn
const auth = createOwnAuth({
tokenPepper: process.env.OWN_AUTH_TOKEN_PEPPER,
passkeys: {
rpId: "example.com",
rpName: "Example",
origins: ["https://example.com"],
},
});rpId is the relying-party domain. Every expected browser origin must be listed in origins.
Register a passkey
Use own-auth/passkeys in browser code:
import { registerPasskey } from "own-auth/passkeys";
await registerPasskey(authClient, {
name: "Laptop",
});Registration requires a valid session and user verification. Discoverable credentials are requested by default. Older non-discoverable authenticators remain supported.
Sign in
Usernameless sign-in works with discoverable credentials:
import { authenticateWithPasskey } from "own-auth/passkeys";
const session = await authenticateWithPasskey(authClient);Non-discoverable credentials require username-first authentication. Resolve the user on the server and pass its ID when requesting options:
const { options } = await auth.beginPasskeyAuthentication({ userId: user.id });Complete MFA with a passkey
When a browser sign-in returns mfa_required and includes passkey:
await authenticateWithPasskey(authClient, { mfa: true });The HTTP handler reads the pending MFA challenge from its HttpOnly cookie. A user-verified passkey creates an aal2 session.
Manage passkeys
const { passkeys } = await authClient.listPasskeys();
await authClient.renamePasskey({
passkeyId: passkeys[0].id,
name: "Work laptop",
});
await authClient.revokePasskey({ passkeyId: passkeys[0].id });Own Auth validates the expected origin, RP ID, challenge, signature, credential ownership, and user verification. Challenges are hashed, expiring, and single-use. Non-zero counters use atomic comparison updates. Valid multi-device credentials whose counters remain zero follow WebAuthn's multi-device rules.