Verifying Signatures
Signature verification confirms a delivery:
- Originated from this service
- Was not modified in transit
- Is recent (replay protection)
Standard Webhooks references:
Headers
Each webhook request includes case-insensitive headers:
webhook-idwebhook-timestampwebhook-signature
Header Semantics
webhook-id: Unique per event, stable across retries, used for idempotency.webhook-timestamp: Unix timestamp (seconds), used for replay checks.webhook-signature: One or more signatures (space-delimited), including rotation overlap cases.
Signature Format
webhook-signature: v1,<sig1> v1,<sig2>- Each signature is
v1,<base64>. - Digest algorithm: HMAC-SHA256.
Signing Input
<webhook-id>.<webhook-timestamp>.<raw-payload>Verification Steps (Production)
- Read the raw request body bytes.
- Extract
webhook-id,webhook-timestamp, andwebhook-signature. - Enforce a timestamp tolerance window (recommended: +/- 5 minutes).
- For each active signing key, compute
v1HMAC over the signing input. - Compare with constant-time equality.
- Accept the request if any signature verifies.
- Deduplicate using
webhook-id.
Reference
Single key:
WEBHOOK_SECRET="whsec_..." cargo runMultiple keys (rotation overlap):
WEBHOOK_SECRET="whsec_old,whsec_new" cargo runCommon Pitfalls
- Parsing and re-serializing JSON before verification.
- Using non-constant-time string comparison.
- Enforcing only one signature during key rotation.
- Ignoring timestamp tolerance checks.