Operations
Key Rotation
Rotate API keys and SES credentials safely.
#Encryption key rotation
The app encrypts webhook secrets and BYOSES credentials at rest with
AES-256-GCM. Rotate ENCRYPTION_KEY periodically and when you suspect
key compromise.
#How ciphertext is versioned
Values written by this repo are tagged with the key version they were encrypted under:
v1:iv:authTag:ciphertext
v1- the currentENCRYPTION_KEYv0- the previousENCRYPTION_KEY_PREVIOUS(only used during rollover)
Legacy values written before the tag was introduced have no prefix and
are assumed v1.
#Rollover procedure
Generate a new key
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Promote the old key to
_PREVIOUSand set the new key as primary# In Convex env npx convex env set ENCRYPTION_KEY_PREVIOUS $OLD_KEY npx convex env set ENCRYPTION_KEY $NEW_KEY # Same values on Cloudflare Worker wrangler secret put ENCRYPTION_KEY_PREVIOUS wrangler secret put ENCRYPTION_KEYDeploy. All new writes are encrypted with the new key (
v1); old values (v0or legacy) still decrypt viaENCRYPTION_KEY_PREVIOUS.Re-encrypt existing ciphertexts You can either:
- Run a one-shot migration that reads each row, decrypts, and re-writes
(forces the
v1tag). Or: - Wait for natural churn: webhook secrets rotate when you rotate them, BYOSES creds rotate on re-connect.
- Run a one-shot migration that reads each row, decrypts, and re-writes
(forces the
Unset the previous key once you're confident nothing
v0-tagged remains:npx convex env remove ENCRYPTION_KEY_PREVIOUS wrangler secret delete ENCRYPTION_KEY_PREVIOUS
#Detecting old ciphertext
import { decryptSecret } from "convex/lib/cryptoWeb";
// Ciphertexts starting with "v0:" are using the previous key.
// Filter webhooks.secret / sesConfigurations.accessKeyId / etc. for those
// and re-encrypt them in a migration script.
#What you must never do
- Don't unset
ENCRYPTION_KEYwithout first re-encrypting everything. The app will lose the ability to decrypt webhook secrets and BYOSES creds. - Don't reuse a previous key value. Treat rotation as strictly forward-only.
- Don't commit keys to git. They live in Convex env + Worker secrets only.