Vault guide
Create a vault, unlock daily, and recover without making the recovery phrase the everyday path.
Vault guide
Product vault UX lives in @railman/zero-vault. The Better Auth plugin only stores wraps you already produced.
Composition
Wire the full stack with Vault composition. This page is the create / unlock / recover ceremony.
Live demo: Vault lab
Create
import { createVaultClient } from "@railman/zero-vault";
const vault = createVaultClient({ userId: session.user.id });
const created = await vault.createVault({
password: vaultPassword, // optional daily method
// prfSecret + encryptionCredentialId after WebAuthn get
accountRecovery: false, // set true for Mode B account+vault
});
// Force export before continuing
created.init.exportRecoveryPhrase();
// Persist:
// POST created.mekBody → /zero-access/mek
// POST each created.dailySlots → /zero-access/wrap-slotsWhat you just did:
- Generated a MEK client-side
- Wrapped it under a recovery KEK (BIP-39)
- Optionally wrapped it under password and/or PRF
- Asked the user to export the phrase
- Sent only ciphertext to the server
Daily unlock
const slots = await fetchWrapSlots(); // GET /zero-access/wrap-slots
const result = await vault.unlockDaily({
slots,
prfSecret, // from extractPrfSecret after WebAuthn
password, // vault password, never sent to server
});
if (!result.ok) {
// not_provisioned | no_daily_method | password_required | ...
}Order of attempts: PRF slots first, then password slots. Recovery slots are ignored here on purpose.
Recovery reset
const unlocked = await vault.resetWithRecoveryPhrase({
slots,
mnemonic,
});
// Immediately re-enroll daily methods so the user is not phrase-dependent
const newDaily = await vault.reenrollDailyMethods({
slots,
mnemonic,
prfSecret,
password,
});
// POST new wraps; revoke lost PRF slots if neededreenrollDailyMethods re-unlocks a short-lived grant MEK (session MEK cannot plant wraps). Pass fresh slots + secrets — do not reuse the session unlocked from resetWithRecoveryPhrase.
Idle lock
MEK session stores support idle timeout (default on the order of 15 minutes). When idle expires, require unlock again — elevate status is unrelated.
UI checklist
| Moment | Product should |
|---|---|
| Create | Force phrase export + confirm storage |
| Daily | Prefer passkey; fall back to vault password |
| Missing daily methods | Prompt re-enroll after recovery, not “paste phrase every day” |
| PRF unsupported | Clear toast; password path if provisioned |