Webhook Signature Verification

Webhook Signature Verification

When receiving webhook notifications from our system, we recommend verifying the signature to ensure the payload's authenticity and integrity. Each webhook request includes a signature header that you can validate against your webhook secret key.

How to Verify Webhook Signatures

Each webhook request includes a signature in the X-Webhook-Signature header. This signature is a HMAC-SHA256 hash of the request body, using your webhook signature key as the secret.

Example Implementation (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  // Create HMAC using your webhook signature key
  const hmac = crypto.createHmac('sha256', secret);
  
  // Update HMAC with the request body (as a string)
  hmac.update(payload);
  
  // Get the digest in hex format
  const computedSignature = hmac.digest('hex');
  
  // Compare the computed signature with the one from the header
  return crypto.timingSafeEqual(
    Buffer.from(computedSignature, 'hex'),
    Buffer.from(signature, 'hex')
  );
}

// Usage in Express.js middleware
app.post('/webhook', (req, res) => {
  const signature = req.header('X-Webhook-Signature');
  const payload = JSON.stringify(req.body); // Must be the raw, unparsed string
  
  if (!verifyWebhookSignature(payload, signature, WEBHOOK_SIGNATURE_KEY)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook payload
  // ...
  
  res.status(200).send('Webhook received');
});

Example Implementation (Python)

import hmac
import hashlib

def verify_webhook_signature(payload, signature, secret):
    """Verify webhook signature using HMAC-SHA256"""
    computed_signature = hmac.new(
        secret.encode('utf-8'),
        payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(computed_signature, signature)

# Usage in Flask
@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Webhook-Signature')
    payload = request.get_data(as_text=True)  # Raw request body
    
    if not verify_webhook_signature(payload, signature, WEBHOOK_SIGNATURE_KEY):
        return 'Invalid signature', 401
    
    # Process webhook payload
    # ...
    
    return 'Webhook received', 200

Security Best Practices

  1. Store your webhook signature key securely and never expose it in client-side code
  2. Use constant-time comparison when verifying signatures to prevent timing attacks
  3. Validate both the signature and payload before processing the webhook
  4. Implement retry logic for webhook handling in case of temporary failures

Finding Your Webhook Signature Key

Your webhook signature key can be found in the Webhooks section of your merchant dashboard. This key is unique to your account and should be kept confidential.