Webhook Signature Verification
Webhook requests include an HMAC-SHA256 signature in theX-Webhook-Signature-256 header that you should verify to ensure authenticity and prevent tampering.
Verification Process
- Extract the signature from the
X-Webhook-Signature-256header (format:sha256=<hex-signature>) - Get the raw request body before parsing
- Calculate the expected signature using your webhook signing secret
- Compare signatures using a timing-safe comparison function
- Process the webhook only if signatures match
Always use the raw request body for verification, not the parsed JSON. Use timing-safe comparison functions to prevent timing attacks.
Implementation Example
Security Best Practices
- Store signing secrets in environment variables, never hardcode them
- Always verify signatures before processing webhook data
- Use timing-safe comparison functions (
crypto.timingSafeEqual()in Node.js,hmac.compare_digest()in Python) - Only accept webhooks over HTTPS
- Log verification failures for security monitoring
- Implement rate limiting on webhook endpoints
Troubleshooting
Signature verification always fails
Signature verification always fails
Cause: Using parsed JSON instead of raw request bodySolution: Use the raw request body string before any parsing:
- Express:
express.raw({ type: 'application/json' })andreq.body.toString() - Flask:
request.get_data(as_text=True) - FastAPI:
await request.body()then.decode('utf-8')
Invalid signature format error
Invalid signature format error
Cause: Missing header or incorrect formatSolution: Verify the
X-Webhook-Signature-256 header is present and starts with sha256=. Check for header case sensitivity in your framework.Character encoding issues
Character encoding issues
Cause: Inconsistent encoding when converting body to stringSolution: Ensure consistent UTF-8 encoding throughout your verification process.