I’m working on developing a Shopify app. I’m trying to verify the Shopify transaction that happened on the app using Shopify’s HMAC authentication verification using this function. The webhook is created through the Shopify Webhook API for the topic app_subscriptions/update and shopifyApiSecret is the Client Secret for our Shopify app. Here’s the snippet of the code we’re using,
async function validateHmac(req: Request) {
let shopifyApiSecret = config.shopifyAppSecret;
let hmac: any = req.headers["x-shopify-hmac-sha256"];
const message = JSON.stringify(req.body);
const generatedHash = crypto
.createHmac("sha256", shopifyApiSecret)
.update(message)
.digest("base64");
console.log({ message, generatedHash, hmac });
const signatureOk = crypto.timingSafeEqual(
Buffer.from(generatedHash),
Buffer.from(hmac)
);
if (signatureOk) {
return true;
} else {
return false;
}
}
We’ve tried comparing both the ways, that is with === as well as using timingSafeEqual, but the function always returns false and the generatedHash and hmac are not equal on inspection. Can anyone let me know if there is anything wrong with this implementation? Thanks in advance.
2
Answers
The issue was with the data we were consuming to generate the message. We were able to solve it by using the express function in our router
and passing the rawBody to the update function.
Here is the implementation we have done in .Net. You can understand the logic from below code: