Rotating Webhook Secrets
Your webhook secret is the shared secret DVS uses to HMAC-sign every webhook delivery. Rotating it periodically (or immediately after any suspected exposure) is good practice.
When to rotate
- Routine rotation: every 12 months by OSIGU policy.
- Immediate rotation: if you suspect the secret has been exposed (committed to a public repo, leaked in logs, employee offboarded with access).
- OSIGU-initiated: if OSIGU's monitoring detects suspicious signing or delivery patterns.
How rotation works
- 1Request rotation
Email support@osigu.com with subject
Webhook secret rotation — <your tenant slug>. Include the reason and the webhook endpoint ID (if you have it). - 2OSIGU issues a new secret
OSIGU's operator runs the admin endpoint and sends you the new plaintext secret via a secure channel (1Password vault link, encrypted email, in-person handoff — never plain email).
- 324-hour grace period
For 24 hours after rotation, DVS continues to accept signature verification on both the new and the previous secret. This avoids dropped messages on in-flight webhooks. After 24 hours, only the new secret is valid.
- 4Update your receiver
Update your environment variable / secret store with the new value. We strongly recommend supporting both secrets simultaneously during the grace period.
Receiver pattern: support two secrets during rotation
This pattern lets you switch secrets without dropped webhooks. Add the previous secret as a fallback for 24 hours, then remove it.
- Python
- Node.js
SECRETS = [
os.environ["DVS_WEBHOOK_SECRET_CURRENT"],
os.environ.get("DVS_WEBHOOK_SECRET_PREVIOUS"), # optional, only during grace window
]
def verify_with_any(raw_body, signature_header, timestamp_header):
for secret in SECRETS:
if secret and verify_dvs_signature(raw_body, signature_header, timestamp_header, secret):
return True
return False
const SECRETS = [
process.env.DVS_WEBHOOK_SECRET_CURRENT,
process.env.DVS_WEBHOOK_SECRET_PREVIOUS, // optional during grace window
].filter(Boolean);
function verifyWithAny(rawBody, signatureHeader, timestampHeader) {
return SECRETS.some((secret) =>
verifyDvsSignature(rawBody, signatureHeader, timestampHeader, secret),
);
}
After 24 hours, remove DVS_WEBHOOK_SECRET_PREVIOUS from your environment.
What DVS does during rotation
- DVS signs all new webhooks with the new secret immediately.
- The previous secret hash is retained for 24h and accepted by your receiver (as long as you implement the fallback above).
- After 24 hours, the previous secret is purged from DVS storage.
What rotation does NOT do
- Doesn't change your webhook URL.
- Doesn't change your endpoint ID.
- Doesn't pause webhook delivery — events continue to flow.
Lost the secret?
If you no longer have the secret (e.g., the only person with access left the company), you can't recover it from DVS — secrets are bcrypt-hashed on our side, never stored in plaintext. Request a rotation; OSIGU issues a fresh one.