Signature Overview
Fanfare uses HMAC-SHA256 to sign webhook payloads. The signature is computed from:- The timestamp of the request
- The raw request body
- Your webhook signing secret
Signature Headers
Each webhook request includes these headers:Verification Process
Step 1: Extract Headers
Step 2: Prepare the Signed Payload
Concatenate the timestamp and the raw request body with a period:Step 3: Compute Expected Signature
Step 4: Compare Signatures
Step 5: Check Timestamp (Recommended)
Prevent replay attacks by rejecting old webhooks:Complete Verification Example
Node.js / Express
Next.js API Route
Python / Flask
Webhook Secrets
Obtaining Your Secret
Your webhook signing secret is provided when you create a webhook endpoint:- Go to Settings > Webhooks in your dashboard
- Create or edit an endpoint
- Copy the signing secret (begins with
whsec_)
Rotating Secrets
To rotate your webhook secret:- Generate a new secret in the dashboard
- Update your server to accept both old and new secrets temporarily
- Verify webhooks are working with the new secret
- Remove the old secret from your server
Security Best Practices
1. Use Timing-Safe Comparison
Always use timing-safe comparison to prevent timing attacks:2. Check Timestamp Age
Prevent replay attacks by rejecting old webhooks:3. Store Secrets Securely
Never commit webhook secrets to version control. Use environment variables:4. Use Raw Body
Parse the body as raw bytes before JSON parsing:5. Log Failed Verifications
Monitor for signature failures which may indicate attacks:Troubleshooting
Signature Mismatch
Common causes:- Wrong secret: Ensure you’re using the correct webhook secret
- Body modification: Middleware may have modified the raw body
- Encoding issues: Ensure consistent UTF-8 encoding
- Header case sensitivity: Some frameworks lowercase headers
Timestamp Validation Failed
If timestamp validation fails:- Check your server’s clock is synchronized (use NTP)
- Verify the timestamp header is being read correctly
- Consider increasing the max age temporarily for debugging