Webhooks & HMAC Signing · Chapter 5 of 5
Rotating secrets
A zero-downtime rotation procedure, with overlapping secrets and a clear rollback.
9 min read
Secrets leak: an engineer pastes one into a ticket, a config file ends up in a public repository, a vendor is breached. You need to rotate without dropping a single webhook — which means a period where two secrets are valid at once.
The overlap procedure
- Generate the new secret in the provider dashboard. Most providers then sign with both secrets, emitting two
v1=values. - Deploy your endpoint with both secrets in its active list. Verification passes if any signature matches any secret.
- Watch metrics until 100% of verifications succeed against the new secret.
- Expire the old secret at the provider, then remove it from your config.
const ACTIVE = [process.env.WH_SECRET_NEW, process.env.WH_SECRET_OLD].filter(Boolean);
function verify(raw: string, header: Parsed) {
return ACTIVE.some((s) =>
header.signatures.some((sig) => safeEqualHex(hmac(s!, `${header.t}.${raw}`), sig)),
);
}Emergency rotation
If a secret is known to be compromised, skip the overlap: rotate at the provider and deploy the new secret immediately, accepting that in-flight webhooks during the deploy will fail and be retried. Afterwards, audit events received in the exposure window — a forged verified event is the one that matters.