Verifying CXone webhook signature headers in Node.js

Setting up a webhook consumer for interaction events. Want to verify the signature to prevent replay attacks. The docs mention the X-Nice-Signature header.

I’m using Node.js with crypto to verify. Here’s the logic:

const crypto = require('crypto');
const signature = req.headers['x-nice-signature'];
const body = req.rawBody;
const hmac = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET);
hmac.update(body);
const calculated = hmac.digest('hex');

The calculated value never matches signature. Even when I log both, they look totally different. I’ve tried using req.body instead of req.rawBody, but that breaks the hash because of JSON parsing.

Is CXone sending the signature in a specific format? The header value looks like a hex string, but maybe it’s base64? Or am I missing a timestamp parameter in the payload?

Tried checking the raw event log in CXone. The payload structure is standard JSON. No extra fields. Just wondering if the secret key needs to be URL encoded or something. Running on AWS Lambda. Timezone is PST.

Stuck on this for two days.