Recovery
Vault-only recovery by default; optional account + vault break-glass.
Recovery
Two product modes
| Mode | When | What the phrase does |
|---|---|---|
| Vault-only (default) | User can still get a session (password, email, another login passkey) | Unwraps the MEK only |
| Account + vault | Passkey is the only practical login factor | Also proves identity via Mode B (challenge-sign preferred) |
Same BIP-39 words; domain-separated derivation so vault KEK material is not the account proof secret.
Mode B (preferred): challenge-sign
Server stores a public key only. Flow:
- Enroll public key while unlocked
- Start → one-time challenge
- Client signs with key derived from mnemonic
- Finish → Secure, HttpOnly
__Host-recovery-session cookie - Exchange that cookie for a short-lived registration-grant cookie
- Run passkey registration and finalize the grant
The mnemonic and both recovery bearers stay out of JSON. Browser code does not copy a bearer into sessionStorage; lookup at rest uses a purpose-separated HMAC, not plain SHA-256. There is no direct recovery-session consume endpoint.
Legacy pbkdf2-proof-v1 is removed — challenge-sign is the only recovery auth path.
Product rules
- Daily UX must not depend on typing the phrase.
- After recovery unlock, re-enroll PRF and/or password wraps immediately.
- Rate-limit start/finish.
- Allowlist recovery session purposes.
Related
- Vault guide
- Plugin contract
- Monorepo depth:
docs/RECOVERY_ACCOUNT_AND_VAULT.md