Secret Rotation
Rotation Schedule
| Secret | Rotation Frequency | Impact of Rotation |
|---|---|---|
JWT_SECRET | Every 90 days | All active sessions invalidated (or none with dual-secret) |
APP_ENCRYPTION_KEY | Annually | Requires data re-encryption migration |
MFA_ENCRYPTION_KEY | Annually | Requires re-encryption migration; users locked out if skipped |
ENROLLMENT_KEY_PEPPER | Annually | All unexpired enrollment keys invalidated |
MFA_RECOVERY_CODE_PEPPER | Annually | All existing MFA recovery codes invalidated |
AGENT_ENROLLMENT_SECRET | Every 90 days | Only affects new enrollments |
SESSION_SECRET | Every 90 days | All active sessions invalidated |
POSTGRES_PASSWORD | Every 90 days | Requires coordinated DB + app restart |
REDIS_URL credentials | Every 90 days | Brief reconnection |
S3_ACCESS_KEY / S3_SECRET_KEY | Every 90 days | None |
CLOUDFLARE_API_TOKEN | Every 90 days | None (existing certs unaffected) |
TURN_SECRET | Every 90 days | Active remote sessions may drop |
METRICS_SCRAPE_TOKEN | Every 180 days | Brief gap in metrics collection |
RESEND_API_KEY / SMTP password | Per provider policy | Brief notification gap |
| Twilio credentials | Per provider policy | Brief SMS notification gap |
ANTHROPIC_API_KEY | Per provider policy | AI assistant unavailable |
| User API keys | User responsibility | Immediate |
Rotating JWT Secret
-
Generate a new secret:
Terminal window openssl rand -base64 64 -
Update
.env.prodwith the newJWT_SECRET -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
All existing JWTs become invalid — users will need to log in again
Rotating App Encryption Key
-
Generate a new key:
Terminal window openssl rand -hex 32 -
Record the old key securely — you need it for the re-encryption migration
-
Run the re-encryption migration:
Terminal window OLD_ENCRYPTION_KEY=<old-key> \APP_ENCRYPTION_KEY=<new-key> \npx tsx scripts/re-encrypt-secrets.ts -
Verify decryption of several records with the new key
-
Update
APP_ENCRYPTION_KEYin.env.prodto the new key -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api
Rotating MFA Encryption Key
-
Generate a new key:
Terminal window openssl rand -hex 32 -
Run a re-encryption migration targeting MFA secret columns (same approach as
APP_ENCRYPTION_KEY) -
Update
MFA_ENCRYPTION_KEYin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api
Rotating Enrollment Key Pepper
-
Generate a new pepper:
Terminal window openssl rand -hex 32 -
Update
ENROLLMENT_KEY_PEPPERin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
Regenerate enrollment keys and redistribute to anyone deploying new agents
Rotating MFA Recovery Code Pepper
-
Generate a new pepper:
Terminal window openssl rand -hex 32 -
Update
MFA_RECOVERY_CODE_PEPPERin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
Notify users to regenerate their MFA recovery codes via Settings, or trigger a bulk regeneration as an admin
Rotating Agent Enrollment Secret
-
Generate a new secret:
Terminal window openssl rand -hex 32 -
Update
.env.prodwith the newAGENT_ENROLLMENT_SECRET -
Restart the API
-
Update any deployment scripts or MDM policies with the new secret
Rotating Session Secret
-
Generate a new secret:
Terminal window openssl rand -base64 64 -
Update
SESSION_SECRETin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
All active sessions are invalidated — users must log in again
Rotating Database Password
-
Generate a new password:
Terminal window openssl rand -base64 24 | tr -d '/+=' -
Update the password in PostgreSQL:
Terminal window docker compose -f docker/docker-compose.prod.yml exec postgres \psql -U breeze -c "ALTER USER breeze PASSWORD 'new-password';" -
Update
POSTGRES_PASSWORDandDATABASE_URLin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api
Rotating Redis Credentials
-
Set or update the Redis password:
Terminal window redis-cli CONFIG SET requirepass "new-redis-password"redis-cli -a "new-redis-password" CONFIG REWRITE -
Update
REDIS_URLin.env.prod:REDIS_URL=redis://:new-redis-password@localhost:6379 -
Restart the API and worker processes:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api worker
Rotating S3 / Object Storage Credentials
-
Create a new access key pair in your S3/R2/MinIO console
-
Update
S3_ACCESS_KEYandS3_SECRET_KEYin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
Verify by uploading and downloading a test file
-
Delete the old access key in your storage provider’s console
Rotating Cloudflare API Token
-
In the Cloudflare dashboard, go to My Profile > API Tokens
-
Create a new token with the same permissions (Client Certificates: Edit for the relevant zone)
-
Update
CLOUDFLARE_API_TOKENin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
Verify by triggering a certificate enrollment or renewal
-
Delete the old token in the Cloudflare dashboard
Rotating TURN Secret
-
Generate a new secret:
Terminal window openssl rand -hex 32 -
Update
TURN_SECRETin both the TURN server configuration and.env.prod -
Restart the TURN server and the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api turn
Rotating Metrics Token
-
Generate a new token:
Terminal window openssl rand -hex 32 -
Update
METRICS_SCRAPE_TOKENin.env.prod -
Update the token file:
Terminal window echo "new-token" > monitoring/secrets/metrics_scrape_tokenchmod 600 monitoring/secrets/metrics_scrape_token -
Restart API and Prometheus:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api prometheus
Rotating Email Provider Credentials
Covers RESEND_API_KEY, SMTP_USER / SMTP_PASS, and MAILGUN_API_KEY.
-
Rotate the credential in the provider’s dashboard (Resend, Mailgun, or your SMTP provider)
-
Update the corresponding env var(s) in
.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
Verify by triggering a test notification (e.g., password reset email)
Rotating SMS Provider Credentials (Twilio)
Covers TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN.
-
In the Twilio console, generate a new Auth Token (or create a new API key pair)
-
Update
TWILIO_ACCOUNT_SIDand/orTWILIO_AUTH_TOKENin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
Verify by triggering a test SMS alert
-
Revoke the old credential in the Twilio console
Rotating Anthropic API Key
-
Generate a new API key in the Anthropic console
-
Update
ANTHROPIC_API_KEYin.env.prod -
Restart the API:
Terminal window docker compose -f docker/docker-compose.prod.yml restart api -
Revoke the old key in the Anthropic console
User API Keys
User-facing API keys are managed through the application, not through environment variables.
- Individual rotation: Users regenerate their API key via Settings > API Keys > Regenerate, or via
POST /api/v1/api-keys - Admin revocation: Admins can revoke any API key via the admin panel or
DELETE /api/v1/api-keys/:id - Bulk revocation: In a security incident, an admin can revoke all API keys; users must generate new ones
No environment variable changes or restarts are required. The old key is immediately invalidated upon regeneration.
Emergency Rotation
If you suspect any secret has been compromised:
- Rotate the compromised secret immediately using the procedures above
- Check audit logs for unauthorized access during the exposure window
- Rotate related secrets — if
JWT_SECRETwas compromised, also rotateSESSION_SECRET; if database credentials leaked, also rotateAPP_ENCRYPTION_KEYin case encrypted data was exfiltrated - Notify affected users if their data may have been accessed
- File a post-incident report documenting the timeline, impact, and remediation