Security Model

Design principles

Ravi’s security model is built around three principles:

  1. Zero-knowledge credential storage — the server never sees plaintext passwords or secrets
  2. Identity isolation — each Identity’s data is scoped and inaccessible from other Identities
  3. Agent-native auth — no desktop apps, no biometric gates, no human-in-the-loop

E2E encryption

What’s encrypted

DataEncryption
Passwords (password, username, notes)E2E encrypted (NaCl SealedBox)
Vault secrets (value, notes)E2E encrypted (NaCl SealedBox)
Email content at restE2E encrypted
Secret/password keys and domainsPlaintext (needed for lookup)
Email content via SSE (real-time)Plaintext (server decrypts for dispatch)

Cryptographic primitives

ComponentAlgorithm
Key derivationArgon2id (time=3, mem=64MB, threads=1)
EncryptionNaCl SealedBox (X25519 + Poly1305)
Nonce derivationBLAKE2b(ephemeralPK || recipientPK, 24 bytes)
Ciphertext format"e2e::<base64>"

Key management

  • PIN — 6-digit numeric, never leaves the client
  • Salt — stored server-side, one per account
  • Private key — derived from PIN + salt, stored in ~/.ravi/auth.json with 0600 permissions
  • Public key — uploaded to server for SealedBox encryption
  • Recovery key — generated at first login, saved to ~/.ravi/recovery-key.txt

Identity isolation

Each Identity is a fully isolated scope:

  • API requests are scoped via X-Ravi-Identity header
  • Server enforces that users can only access their own Identities
  • Each Identity has its own email address, phone number, and vaults
  • No cross-Identity data access is possible through the API
  • Disabling an Identity revokes all its access

Authentication security

Token model

TokenScopeLifetime
Access token (JWT)Unbound (no Identity embedded)1 hour
Refresh tokenPer-userLong-lived
Identity scopingX-Ravi-Identity headerPer-request

Access tokens are unbound — they don’t embed a specific Identity. The Identity is specified per-request via the header. This allows switching Identities without re-authenticating.

Credential storage

  • Tokens stored in ~/.ravi/auth.json with 0600 permissions
  • Encryption keypair stored alongside tokens
  • Per-project Identity override via .ravi/config.json in project directory

Comparison with alternatives

Security propertyRaviPlain text files1Password for agents
Credentials encrypted at restYes (E2E)NoYes
Server can read credentialsNo (zero-knowledge)N/ANo
Requires desktop appNoNoYes
Human-in-the-loop requiredNoNoYes (biometric, session unlock)
Session expiry interrupts agentNoN/AYes
Per-agent isolationYes (Identities)NoPartial (vaults)

Threat model

What Ravi protects against

  • Server breach — encrypted vaults are unreadable without the PIN
  • Credential reuse — each Identity has its own vault, no shared credentials
  • Identity conflation — agents don’t use your personal email or phone
  • Inbox pollution — agent subscriptions stay in the agent’s inbox
  • Privacy leakage — your personal info isn’t shared with services the agent uses

What Ravi does not protect against

  • Client-side compromise — if an attacker has access to ~/.ravi/auth.json, they can read the stored keypair
  • Weak PINs — 6-digit PINs have limited entropy; the Argon2id parameters provide the primary brute-force resistance
  • CAPTCHAs — Ravi provides identity, but services may still gate signups with CAPTCHAs
  • Service-level blocking — services may detect and block automated signups regardless of having valid identity

Best practices

  1. Back up your recovery key~/.ravi/recovery-key.txt is your only way to recover if you forget your PIN
  2. Use per-project configs — scope Identities to projects to prevent accidental cross-contamination
  3. Use separate Identities — one per agent or role, so a compromise is contained
  4. Don’t share PINs — each user should have their own Ravi account and PIN
  5. Monitor your inboxes — check for unexpected messages that might indicate misuse