Cannot verify webhook HMAC in Koa

Solved
Highlighted
Tourist
8 1 2

I am trying to verify my api secret for webhook requests in my Shopify app, but simply cannot get the two HMAC on the request and my token digest to match. Here is my code:

 

const verifyShopifyHook = ctx => {
  const { query } = ctx;
  const { hmac: _hmac, signature: _signature, ...map } = query;

  const orderedMap = Object.keys(map)
    .sort((value1, value2) => value1.localeCompare(value2))
    .reduce((accum, key) => {
      accum[key] = map[key];
      return accum;
    }, {});
  const message = querystring.stringify(orderedMap);

  let digest = crypto

    .createHmac("sha256", process.env.SHOPIFY_API_SECRET_KEY)
    .update(message, "utf8")
    .digest("base64");

  return digest === ctx.headers["x-shopify-hmac-sha256"];
};

I am definitely using the right tokens. Can anyone see what I am doing wrong?

0 Likes
Highlighted
Shopify Staff
Shopify Staff
1040 139 163

Hey @Paul91,

 

I had an issue with this recently - the trick was to use the raw body (before it's turned into a string) or escape the backslashes.

 

More info: https://community.shopify.com/c/Shopify-APIs-SDKs/Can-t-verify-Webhooks-in-Node-js-serverless-AWS-la...

 

Let me know how you go.

1 Like
Highlighted
Tourist
8 1 2

This is an accepted solution.

Yep, the addition of rawBody ended up being the ticket. Here is my final implementation if anyone else runs across this:
 
const verifyShopifyHook = ctx => {
  const { headers, request } = ctx;
  const { "x-shopify-hmac-sha256": hmac } = headers;
  const { rawBody } = request;

  const digest = crypto
    .createHmac("SHA256", process.env.SHOPIFY_API_SECRET_KEY)
    .update(new Buffer(rawBody, "utf8"))
    .digest("base64");

  return safeCompare(digest, hmac);
};
1 Like