Skip to main content

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
Always verify webhook signatures in production. Unverified webhooks can lead to security vulnerabilities and data integrity issues.

How it works

When you create a webhook subscription, the response includes a secret that serves as your signing key. Each webhook request includes the signature under the header name: X-Hook0-Signature.
Example signature header
The signature header contains four parts:
v0 and v1 are both included on every request. v0 includes the timestamp and body; v1 additionally binds the listed headers. Unless you want to bind the headers, which is unnecessary for most use cases, use v0.
  1. Extract signature components: Parse the t, h, v0, and v1 values from the header
  2. Build signed payload: Concatenate timestamp.headerNames.headerValues.rawBody
  3. Compute expected signature: Create HMAC-SHA256 hash using your secret
  4. Compare signatures: Use timing-safe comparison to match expected vs. provided
  5. 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
The webhook request will include these HTTP headers:
HTTP headers

Security best practices

Never hardcode webhook secrets in your code. Use environment variables or a secure secrets manager:
Always use HTTPS endpoints for your webhooks. HTTP endpoints expose your webhook data to interception and tampering.
Add rate limiting to your webhook endpoint to prevent abuse:
The default 5-minute window prevents replay attacks. Adjust based on your needs, but don’t make it too large:
Track failed verification attempts to detect potential security issues:

Error handling

Handle common verification failures gracefully:
error-handling.js