Zero Accessby Railmandocs

WebAuthn and PRF

Introductory reading on WebAuthn jobs in this suite and how the PRF extension unlocks a vault without sending secrets to the server.

WebAuthn and PRF

Extended reading on why this suite leans on WebAuthn and the prf extension — not a shipping checklist. Integration steps live in Passkeys and PRF. Primitive inventory: Crypto primitives. Design and upstream rationale: Crypto and package rationale.

Stage

Packages are pre-1.0. Prefer the security model before production use. Security is hard; this is an open foundation.

The product idea

Keys that open user data stay on the device. The server stores wraps, claims, and sealed envelopes. WebAuthn is how a passkey proves presence for login or step-up. When the authenticator supports PRF, the same credential family can also derive a site-bound secret for daily vault unlock — without sending that secret to your backend.

Two WebAuthn jobs

Mixing these jobs in UX is fine. Mixing their crypto outputs is not.

JobLayerWhat the authenticator provesWhat the server learns
Login / elevateL0 / L1User presence + credential bindingAssertion material for session or step-up claim
Vault unlock (PRF)L2Same credential family, plus PRF output in the browserOnly wrap ciphertext / metadata after unlock

Elevate never receives the storage PRF secret. Vault unlock never grants admin routes. That separation is L0 · L1 · L2 — see How it works.

Hardened composition lives in @railman/auth-zero-access-passkey (enhancePasskey): frozen RP/origin posture, user verification, and a counter guard shared with passkey step-up when you enable it. Package guide: Passkey.

What PRF is (and is not)

PRF here means the WebAuthn prf extension: the authenticator derives bytes bound to your RP and a salt/info you choose in the browser. Those bytes stay in the page. They become a KEK that unwraps the MEK.

PRF isPRF is not
A daily unlock factor when the authenticator supports itA replacement for TLS
Domain-separated with purpose + userId (and resource id)Something the blind store is allowed to see
Degradable — missing PRF → password or recovery UXMagically available on every device

Tenant salt and suite helpers live in the browser via defineZeroAccessPasskeyCryptoConfig. Ceremony: extensions → navigator.credentials.getextractPrfSecret → unlock — documented in Passkeys and PRF. Glossary: Background.

Domain separation (why it matters)

PRF/HKDF info strings bind purpose and user:

prefix | purpose | userId | [resourceId] | [suffix]

userId is required. Purposes such as storage_kek and elevate-related derivations must not be interchangeable. Cross-user mixups must fail closed.

Where to go next

On this page