Ravi’s security model is built around three principles:
Zero-knowledge credential storage — the server never sees plaintext passwords or secrets
Identity isolation — each Identity’s data is scoped and inaccessible from other Identities
Agent-native auth — no desktop apps, no biometric gates, no human-in-the-loop
E2E encryption
What’s encrypted
Data
Encryption
Passwords (password, username, notes)
E2E encrypted (NaCl SealedBox)
Vault secrets (value, notes)
E2E encrypted (NaCl SealedBox)
Email content at rest
E2E encrypted
Secret/password keys and domains
Plaintext (needed for lookup)
Email content via SSE (real-time)
Plaintext (server decrypts for dispatch)
Cryptographic primitives
Component
Algorithm
Key derivation
Argon2id (time=3, mem=64MB, threads=1)
Encryption
NaCl SealedBox (X25519 + Poly1305)
Nonce derivation
BLAKE2b(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
Token
Scope
Lifetime
Access token (JWT)
Unbound (no Identity embedded)
1 hour
Refresh token
Per-user
Long-lived
Identity scoping
X-Ravi-Identity header
Per-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 property
Ravi
Plain text files
1Password for agents
Credentials encrypted at rest
Yes (E2E)
No
Yes
Server can read credentials
No (zero-knowledge)
N/A
No
Requires desktop app
No
No
Yes
Human-in-the-loop required
No
No
Yes (biometric, session unlock)
Session expiry interrupts agent
No
N/A
Yes
Per-agent isolation
Yes (Identities)
No
Partial (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
Back up your recovery key — ~/.ravi/recovery-key.txt is your only way to recover if you forget your PIN
Use per-project configs — scope Identities to projects to prevent accidental cross-contamination
Use separate Identities — one per agent or role, so a compromise is contained
Don’t share PINs — each user should have their own Ravi account and PIN
Monitor your inboxes — check for unexpected messages that might indicate misuse