Your generic HMAC SHA-256 signature logic consistently fails when validating custom integrations.
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 });
});Determine encoding → read raw payload → generate HMAC → timing-safe compare.
Works with webhooks and other async event systems (including AI callbacks). Instead of guessing, inspecting the exact payload and headers can help debug faster.
Try the free webhook testerWas this page helpful?
Your feedback helps us improve the docs.