Encrypted secret storage for Convex with envelope encryption, key rotation, expiry, audit logs, and namespace-scoped organization.
npm install convex-secret-storeEncrypted secret storage for Convex using envelope encryption and versioned KEKs.
Features:
- namespace-scoped secrets
- per-secret DEKs with AES-GCM
- key rotation without rewriting plaintext
- expiry and cleanup flows
- audit log for writes and maintenance operations
- typed TypeScript client
Includes a full example app showing secret management, safe server-side usage, activity history, and rotation/cleanup workflows.
Use the Convex Secret Store component to encrypt API keys with envelope encryption. Store secrets with `secrets.put(ctx, { namespace: 'app:production', name: 'openai', value: apiKey })` and retrieve them with `secrets.get()`. Each secret uses a unique data encryption key wrapped by your master key.
The Convex Secret Store supports key rotation without rewriting encrypted data. Add new key versions to your configuration, then use `secrets.rotateKeys()` to rewrap existing secrets under the new key. Old keys remain available for decryption during the transition.
Organize secrets by namespace like `workspace:production` or `team:testing`. The TypeScript client enforces namespace patterns at compile time while storing secrets separately per namespace for isolation and access control.
The component automatically logs all secret operations (create, update, delete, rotate) to an append-only audit table. Use `secrets.listEvents()` to paginate through audit history filtered by namespace, secret name, or operation type for compliance tracking.
Convex Secret Store uses envelope encryption with two layers: each secret gets a unique AES-GCM data encryption key (DEK), and that DEK is wrapped with your configured key encryption key (KEK). This allows key rotation by rewrapping DEKs without touching the encrypted secret data.
Yes, Convex Secret Store supports zero-downtime key rotation. Add the new key version as the first entry in your keys array, deploy, then use the `rotateKeys()` method to rewrap existing secrets. Old keys remain available during the transition period.
The Convex Secret Store automatically handles expiry during reads - expired secrets return `{ ok: false, reason: 'expired' }`. Use the `cleanupSecrets()` method with a retention window to permanently delete expired secrets, and set up a cron job to run cleanup regularly.
If you remove a key version from your configuration, secrets encrypted with that version become unreadable and return `{ ok: false, reason: 'key_version_unavailable' }`. Always rotate secrets to newer key versions before removing old keys from your configuration.
Use namespaces to separate secrets by environment or team, like `myapp:production` or `team-alpha:testing`. The Convex Secret Store TypeScript client can enforce namespace patterns at compile time while keeping secrets isolated at runtime.