Building a webhook consumer to handle routing.queue.member events. We’ve got the endpoint set up and receiving payloads, but I’m trying to add signature verification to prevent replay attacks. The docs say the header X-Genesys-Signature contains a base64-encoded HMAC-SHA256 of the request body using the webhook secret.
Here’s the verification logic I’ve written in Express:
const crypto = require('crypto');
app.post('/webhook', (req, res) => {
const signature = req.headers['x-genesys-signature'];
const payload = JSON.stringify(req.body);
const hmac = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET);
hmac.update(payload);
const digest = hmac.digest('base64');
if (signature !== digest) {
return res.status(401).send('Invalid signature');
}
res.status(200).send('OK');
});
The check always fails. I logged both values and they look totally different. The header value starts with sha256=, which I’m stripping before comparison. I’ve tried using req.body as a string, JSON stringified, and even the raw buffer. Nothing matches.
Is there a specific encoding step I’m missing? Or is the secret being passed in a different format than I think? I’ve double-checked the secret in the Genesys UI and it matches what’s in my env var.