Integration checklist
Ship a zero-access vault without collapsing L0, L1, and L2.
Integration checklist
Use this when wiring packages into a product app.
Architecture
- L0 session, L1 elevate, and L2 vault unlock are separate code paths
- No route unlocks MEK because elevate succeeded
- No route grants admin because MEK is unlocked
-
requireAccess/ elevate maps are server constants, not query/body input
Server
- Only install packages for your use case (A–E)
- Passkeys:
enhancePasskey(passkey, { rpID, origin, assertCredentialAccess, ... })→...stack.plugins - Passkey step-up:
elevate({ passkeyCounterGuard: stack.controller, ... })— omit guard for password/TOTP-only - Vault:
zeroAccess({ deploymentMode, ... })in the same Better Auth instance as...stack.plugins -
loginFactors()if you use distinct-factor gates - Posture graduated: step-up
assertCredentialAccess,securityLevel: "strict"— assertstack.posturein CI - Persistent authority chosen: omit
zeroAccess.secretto capture Better Auth's secret, or provide one stable Railman root - Multi-instance: shared stores + conformance capabilities (not process
Maponly) -
BETTER_AUTH_URL/rpID/originmatch the real host for WebAuthn`
Client vault
-
defineZeroAccessPasskeyCryptoConfig({ salt })with a stable tenant salt -
createVaultClient({ passkeyOptions: cryptoConfig }) - Create vault forces recovery phrase export before continue
- Daily unlock uses PRF and/or password — not the mnemonic
- Password wraps use ≥ 600_000 PBKDF2 iterations
- After recovery reset, immediately re-enroll daily methods
- MEK idle lock configured; clear on logout
- PRF unavailable shows a human error + password fallback if provisioned
HTTP / M6
- Never POST mnemonic, raw MEK, PRF secret, or vault password
- Recovery bearers stay in Secure, HttpOnly
__Host-cookies; no JSON orsessionStoragecopy - Wrap puts go to
/zero-access/wrap-slotswith session cookies - Revoke lost encryption credentials without ending the BA session
Product copy
- “Step up” vs “Unlock vault” are different buttons and screens
- Recovery is labeled break-glass / reset, not “login with phrase”
- Demo/lab banners if using disposable hosted storage
Verify
pnpm ci:core # hosted-equivalent core plugin gate
pnpm test:security # monorepo matrix only
# manual: create → unlock → elevate-only action → recovery reset- Exact Better Auth
1.6.27(no peer range on core plugins) - Chat / E2E uses
initiateSessionPinned(not unpinnedinitiateSession)