Skip to content

Recovery Key

The recovery key is the master encryption key for your data.

ABCD-EFGH-IJKL-MNOP-QRST-UVWX-YZ23-4567-ABCD-EFGH-IJKL-MNOP-Q
  • 52 characters (excluding dashes)
  • Base32-like alphabet (A-Z, 2-7)
  • ~256 bits of entropy
  • Human-readable (no confusable chars like 0/O, 1/I)
PropertyValue
User-controlledOnly you know it
Not transmittedNever sent to server
Not recoverableServer cannot help if lost
PortableWorks across devices
import { generateRecoveryKey } from "@zod-vault/crypto";
const recoveryKey = generateRecoveryKey();

Uses crypto.getRandomValues() for cryptographic randomness.

import { validateRecoveryKey } from "@zod-vault/crypto";
if (validateRecoveryKey(userInput)) {
// Valid format
}

Store in your password manager (1Password, Bitwarden, etc).

Print and store in a safe location:

╔═══════════════════════════════════════════════════╗
║ zod-vault Recovery Key ║
║ ║
║ ABCD-EFGH-IJKL-MNOP-QRST-UVWX-YZ23-4567 ║
║ ABCD-EFGH-IJKL-MNOP-Q ║
║ ║
║ Store this safely. It's the only way to ║
║ decrypt your data. ║
╚═══════════════════════════════════════════════════╝

For high security, split the key:

const key = "ABCD-EFGH-IJKL-MNOP-QRST-UVWX-YZ23-4567-ABCD-EFGH-IJKL-MNOP-Q";
// Store separately
const part1 = key.slice(0, 26); // First half
const part2 = key.slice(26); // Second half
  • Store unencrypted on cloud storage
  • Email to yourself
  • Share via unencrypted chat
  • Use a weak/guessable key
  • Reuse across different vaults

Consider separate keys for different vaults:

const personalKey = generateRecoveryKey();
const workKey = generateRecoveryKey();
// Personal vault
vault(config, { name: "personal", recoveryKey: personalKey });
// Work vault
vault(config, { name: "work", recoveryKey: workKey });

Compromise of one key doesn’t affect the other.

If you lose your recovery key:

  1. Your data cannot be recovered
  2. The server cannot help (zero-knowledge)
  3. Create a new vault with a new key
  4. Start fresh

This is by design — true E2EE means no backdoors.

To change your recovery key:

  1. Generate new key
  2. Decrypt data with old key
  3. Re-encrypt with new key
  4. Update vault on server
// Manual rotation
const oldData = await useStore.vault.pull();
const newKey = generateRecoveryKey();
// Create new store with new key
const newStore = create(
vault(config, {
name: "migrated-store",
recoveryKey: newKey
})
);
newStore.setState(oldData);
await newStore.vault.push();
// Clear old vault
await useStore.vault.clearStorage();