Data and secrets
Manage application secrets
Keep credentials out of source code and logs, scope them narrowly, rotate them, and make local and production access deliberate.
API keys, signing keys, database passwords, and webhook secrets are credentials. Treat them as temporary authority, not configuration text.
The difference matters. Configuration describes how the app behaves. A secret is power: whoever holds it can act as your application. Power needs an owner, a scope, and a revocation plan.
Where secrets live
Three rules cover storage:
- Production secrets belong in the platform secret manager, injected as environment variables or bindings at runtime, only into the services that need them.
- Local development uses a gitignored
.envfile with development-only values. - Nothing secret ever ships to browser code. If JavaScript in the browser can read it, so can every visitor.
Source code is the classic leak. Once a key is committed, it lives in git history even after you delete it from the current file. Rotate any secret that was ever committed, then add scanning so it does not happen again:
echo ".env" >> .gitignore
npx gitleaks git .
# scans the repository history for committed credentials
One key, three consumers
One shared API key powers development, production, and a contractor script. It works fine until the provider flags abuse. Now you have two bad options: revoke the key and stop all three systems at once, or leave it live while you investigate. And the sharing means you cannot even tell which consumer caused the abuse.
Separate secrets add rotation work. They also let us revoke one integration without turning a small leak into a full outage. One consumer, one credential.
Rotation is a muscle
A secret you cannot rotate is a time bomb. Plan the leak before it happens: for each production secret, know the owner, the scope, every consumer, and the exact rotation procedure.
secret: STRIPE_WEBHOOK_SECRET
owner: payments team
scope: verify webhook signatures only
consumers: app server (production)
rotate: provider dashboard -> roll secret -> update secret manager -> deploy
Then rehearse it in a test environment. Rotate the secret, prove the new value works, and prove the old value fails. The second half is the part teams skip — and it is the only part that tells you revocation actually revokes.
Lesson completed