---
id: TASK-86
title: Encrypted server-side account vault for EncryptID
status: Done
assignee: []
created_date: '2026-03-03 19:15'
updated_date: '2026-03-03 19:15'
labels:
  - encryptid
  - security
  - feature
dependencies: []
references:
  - src/encryptid/vault.ts
  - src/encryptid/server.ts
  - shared/local-first/crypto.ts
  - server/local-first/backup-routes.ts
priority: high
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Zero-knowledge vault stores all EncryptID account data (profile, emails, devices, addresses, wallets, preferences) as a single AES-256-GCM encrypted JSON blob via the backup API. Key derived deterministically from WebAuthn PRF via HKDF — same passkey = same key on any device. Server never sees plaintext.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 VaultManager class with AccountVault interface, DocCrypto encryption, backup API storage, localStorage cache
- [x] #2 Vault auto-loads on passkey auth (handleLogin + conditionalUI), clears on logout
- [x] #3 Dashboard UI: checklist item, vault section with Save/Restore buttons, status display
- [x] #4 Save triggers passkey re-auth → AES-256-GCM encrypt → PUT /api/backup/__vault/account-vault
- [x] #5 Restore triggers passkey re-auth → GET → decrypt → populate DOM
- [x] #6 checkVaultStatus() on profile load updates checklist green check
- [x] #7 No new server routes or DB tables — uses existing backup API
- [x] #8 tsc --noEmit and vite build pass clean
<!-- AC:END -->

## Final Summary

<!-- SECTION:FINAL_SUMMARY:BEGIN -->
## Files Created\n- `src/encryptid/vault.ts` — VaultManager class, AccountVault interface, singleton pattern\n\n## Files Modified\n- `src/encryptid/index.ts` — Export vault types and functions\n- `src/encryptid/ui/login-button.ts` — Load vault after auth, clear on logout\n- `src/encryptid/server.ts` — Dashboard vault section, checklist item, inline crypto functions (deriveVaultKey, saveVault, restoreVault, checkVaultStatus)\n\n## Key Design\n- Vault key: `Master PRF → HKDF("rspace:__vault") → HKDF("doc:account-vault") → AES-256-GCM`\n- Dashboard uses inline WebCrypto (not VaultManager import) since dashboard auth doesn't initialize DocCrypto\n- Save/restore require biometric re-auth for security\n\nCommit: e2e12af, deployed to production.
<!-- SECTION:FINAL_SUMMARY:END -->
