Custom HMAC Webhook Validation Failed? Fix Guide

Complete guide to webhooks, debugging, and real-time event monitoring with HookMetry

Custom HMAC Webhook Validation Failed? Fix Guide

Problem Introduction

Your generic HMAC SHA-256 signature logic consistently fails when validating custom integrations.

Why It Happens

  • Empty bodies producing unexpected hashes
  • Middleware modifying raw request bytes
  • Encoding mismatch — sender uses base64, you compute hex (or vice versa)

Step-by-Step Fix

  1. 1Confirm with the sender whether the signature is hex or base64 encoded.
  2. 2Skip validation if the request body is genuinely empty — hashing empty string gives a predictable digest.
  3. 3Use express.raw() or equivalent to receive the payload as unmodified bytes.
  4. 4Compute HMAC-SHA256 with the correct encoding and compare using timing-safe equal.

Working Code

Copy-paste verified examples. Use the tab that matches your stack.

const crypto = require('crypto');

app.post('/webhooks/custom', express.raw({ type: '*/*' }), (req, res) => {
  const receivedSig = req.headers['x-webhook-signature'] || req.headers['x-signature'];
  if (!receivedSig) return res.status(400).send('No signature header');

  // Check with sender: is the signature hex or base64?
  const encoding = 'hex'; // change to 'base64' if required by the provider

  const expectedSig = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(req.body)
    .digest(encoding);

  // Timing-safe comparison — both buffers must have the same encoding
  let valid = false;
  try {
    const a = Buffer.from(receivedSig, encoding);
    const b = Buffer.from(expectedSig, encoding);
    valid = a.length === b.length && crypto.timingSafeEqual(a, b);
  } catch { valid = false; }

  if (!valid) return res.status(401).send('Signature mismatch');

  const payload = JSON.parse(req.body);
  res.status(200).json({ ok: true });
});

Common Mistakes

  • Defaulting to `hex` when the sender uses `base64`
  • Comparing hashes with `===` instead of timing-safe variants.

Debugging Workflow

Determine encoding → read raw payload → generate HMAC → timing-safe compare.

Preventive Best Practices

  • Easily distinguish generic structural and prefix discrepancies out-of-the-box with Hookmetry.

Works with webhooks and other async event systems (including AI callbacks).

Instead of guessing, inspecting the exact payload and headers can help debug faster. Tools like Hookmetry support this workflow.

Try the free webhook tester

Was this page helpful?

Your feedback helps us improve the docs.