I'm trying to secure my Zoho webhook implementation. I followed this doc: https://www.zoho.com/subscriptions/kb/webhooks/securing-webhooks.html
I don't find it super clear on what to do, but I'm pretty sure that in the end I still did everything what they said.
I DONT have any query parameters. The format is just a default JSON payload NO X-WWW-FORM-URLENCODED.
I tried with following code, but I don't get the correct hash. It's also unclear if I should sort the default payload or not. According to this answer, it's only necessary for form-url-encoded and query parameters, but for plain JSON payload is no processing required. Either way I tried both ways with following implementation as a result:
function computeZohoSignature(query, payload) {
return crypto
.createHmac('sha256', process.env.ZOHO_WEBHOOK_SECRET)
.update(JSON.stringify(payload), 'utf8')
.digest('hex');
}
function validSignature(signatureHash, computedHash) {
return signatureHash.length === computedHash.length
&& crypto.timingSafeEqual(Buffer.from(signatureHash), Buffer.from(computedHash));
}
I also tried wrapping the payload with following function:
function sortObjectByKeys(object) {
if (!isObject(object)) return object;
const sortedObj = {};
Object
.keys(object)
.sort()
.forEach((k) => {
sortedObj[k] = sortObjectByKeys(object[k]);
});
return sortedObj;
}
The sorting works correct, and I even tried with just sorting the "root-keys". Doesn't matter what I try, the hash is never the same. And YES I'm 100% certain the secret is correct, I triple checked that.
Does anyone see what's wrong here or has a working NodeJS implementation of doing this?
Thanks in advance!