Secrets and token handling
Where secrets live, how they leak, and the lifetime rules for tokens and keys.
Secrets and token handling
Secrets are credentials: passwords, API keys, connection strings, certificates, signing keys. The lifecycle rules that keep them yours:
Storage. Secrets never live in source control (.env files in repos
are how keys leak โ the repo outlives the rotation schedule), never in
logs, never in exception messages, never in URLs. In production: a secret
store (cloud key vaults, Docker secrets, mounted files) injected as
environment or file references the app reads at startup. In development:
user-secrets (dotnet user-secrets), which lives outside the repo.
Rotataion and blast radius. Assume every secret leaks eventually. The design questions: how fast can it be rotated (minutes, not redeploys), and what else does it unlock (one scoped key per dependency beats one master key)? Short-lived credentials beat long-lived ones โ that is the entire pitch of workload identity / OIDC federation.
Tokens. Bearer tokens (JWT or opaque) are time-boxed authority:
- Short expiry (minutes) with refresh โ a leaked access token dies quickly.
- Audience + issuer checks on every verification โ a token minted for service A must not authorize service B (the confused-deputy bug).
- Sign, never encrypt-then-forget-verification; verify algorithm
allow-list explicitly (
alg: noneand algorithm-confusion attacks are real). - Opaque tokens verified server-side trade a lookup for revocability; JWTs trade revocability for zero lookup. Pick per use case โ but pick, and write the decision down.
Logging discipline is half of secret safety in practice: structured
log scrubbers that redact keys before emission, and the code-review rule
that ToString() on a credentials object never goes near a log line.