Rotating and safely storing secrets

Secret Rotation Security Key management
Who this article is for
For operators who want to periodically update (rotate) the secrets of an app running in production.

A secret has the property that "the longer you keep using the same one, the more leak risk accumulates". A departed member viewed it in the past, it slipped into a log, it was carried out in a backup — all of these are plausible paths. The basic strategy is to bound the blast radius of a leak by time through periodic rotation.

Guideline rotation frequency

Target Recommended frequency Triggers for immediate update
Client secretOnce a yearSuspected leak, offboarding, a leak incident
Webhook secretOnce a yearSame as above
Access tokenAutomatic (1 hour)
Refresh tokenAutomatic (90 days)

Client secret rotation procedure

ReceiptRoller supports a "parallel period for the old and new secrets", so you can rotate with zero downtime.

  1. Developer portal → App → Credentials → "Issue an additional secret"
  2. Store the new secret securely
  3. Update the value in your secret management service (AWS Secrets Manager, etc.) to the new secret
  4. Deploy the production environment in sequence (or reflect the environment variable via a rolling restart)
  5. Confirm via logs that all environments are running on the new secret
  6. "Revoke" the old secret in the developer portal

During the parallel period, both secrets are valid. Even if a request arrives with the old secret in the middle of a deploy, authentication passes, so the switch can be done with zero downtime.

Webhook secret rotation

The Webhook secret can also be operated with a parallel period. Implementing the receiving side to "try signature verification with both the old and new secrets" makes the switchover window safe.

function verify(body, signature, ts) {
  return verifyWith(body, signature, ts, NEW_SECRET)
      || verifyWith(body, signature, ts, OLD_SECRET);
}

After the switch is complete, remove the reference to OLD_SECRET from the code.

Storage best practices

  • Use a secret management service: AWS Secrets Manager / Azure Key Vault / GCP Secret Manager / HashiCorp Vault
  • Encrypt environment variables: use the encryption feature when registering them in CI (GitHub Secrets, GitLab CI Variables, etc.)
  • Access auditing: keep it in a state where you can trace who retrieved a secret and when
  • Least privilege: only production service accounts can retrieve production secrets
  • Exclude from backups: do not include secrets in DB backups or log archives
  • Offboarding: immediately rotate secrets a departing member had access to

Things you must not do

Anti-pattern What to do
Committing a .env file to gitAdd it to .gitignore; delete any past inclusion per-history + regenerate the secret
Sharing secrets over Slack or emailShare via a secret management service
Embedding in client-side codeMove it to the server side; regenerate immediately
Outputting secrets to error logsMasking, delete logs, regenerate
Using the same secret for yearsPut an annual rotation on the calendar

Related guides

Published: 2026-04-27 Updated: 2026-07-05