Overview
Verifying webhook signatures ensures that incoming webhooks are authentic and sent by Coinbase, protecting your application from malicious requests and replay attacks.Why verify signatures?
Without signature verification, your webhook endpoint is vulnerable to:- Spoofed webhooks: Attackers could send fake event data to your endpoint
- Replay attacks: Old webhook events could be resent to trigger duplicate processing
- Man-in-the-middle attacks: Modified webhook payloads could go undetected
How it works
When you create a webhook subscription, the response includes asecret that serves as your signing key.
Each webhook request includes the signature under the header name: X-Hook0-Signature.
Example signature header
Verification process
Verification process
- Extract signature components: Parse the
t,h,v0, andv1values from the header - Build signed payload: Concatenate
timestamp.headerNames.headerValues.rawBody - Compute expected signature: Create HMAC-SHA256 hash using your secret
- Compare signatures: Use timing-safe comparison to match expected vs. provided
- Verify timestamp: Ensure the webhook isn’t too old (prevents replay attacks)
1. Create a verification function
First, handle the verification logic in a reusable function which will:- Parse the signature header to extract the timestamp, header names, and signature
- Build the signed payload by concatenating the timestamp, headers, and raw body
- Compute the expected signature using HMAC-SHA256
- Compare the signatures using a timing-safe comparison to prevent timing attacks
- Validate the timestamp to ensure the webhook isn’t too old (replay attack prevention)
verify-webhook.js
2. Verify webhooks in your application
Now integrate the verification function into your webhook endpoint. This example shows:- How to configure Express to preserve the raw request body (required for signature verification)
- How to extract the signature header and webhook secret
- How to call the verification function before processing the webhook
- How to handle both valid and invalid webhooks appropriately
Important: You must use
express.raw() middleware instead of express.json() to preserve the raw request body. The signature is computed against the raw bytes, so parsing the JSON first will break verification.webhook-endpoint.js
Example webhook payload
Here’s what a complete webhook request looks like:webhook-payload.json
HTTP headers
Security best practices
Store secrets securely
Store secrets securely
Never hardcode webhook secrets in your code. Use environment variables or a secure secrets manager:
Use HTTPS only
Use HTTPS only
Always use HTTPS endpoints for your webhooks. HTTP endpoints expose your webhook data to interception and tampering.
Implement rate limiting
Implement rate limiting
Add rate limiting to your webhook endpoint to prevent abuse:
Validate timestamp window
Validate timestamp window
The default 5-minute window prevents replay attacks. Adjust based on your needs, but don’t make it too large:
Log verification failures
Log verification failures
Track failed verification attempts to detect potential security issues:
Error handling
Handle common verification failures gracefully:error-handling.js
What to read next
- Quickstart: Set up your first webhook subscription.
- Webhooks overview: All webhook surfaces and shared concepts.