6

I cannot able to validate the webhook response from the shopify by using the "shopify-node-api". and i am using the following code to validate the signature.

Below code is on app.js

app.use(bodyParser.json({
type:'application/json',
limit: '50mb',
verify: function(req, res, buf, encoding) {
     if (req.url.startsWith('/webhook')){
         req.rawbody = buf;
     }
   }
 })
);
app.use("/webhook", webhookRouter);

Below on webhook.router.js

router.post('/orders/create', verifyWebhook, async (req, res) => {    
    console.log('🎉 We got an order')
    res.sendStatus(200)
 });

Below for the verification function

function verifyWebhook(req, res, next) {
  let hmac;
  let data;
  try {
    hmac = req.get("X-Shopify-Hmac-SHA256");
    data = req.rawbody;
  } catch (e) {
    console.log(`Webhook request failed from: ${req.get("X-Shopify-Shop-Domain")}`);
    res.sendStatus(200);
  }
  if (verifyHmac(JSON.stringify(data), hmac)) { // Problem Starting from Here
    req.topic = req.get("X-Shopify-Topic");
    req.shop = req.get("X-Shopify-Shop-Domain");
    return next();
  }

  return res.sendStatus(200);
}

Verify signature function

function verifyHmac(data, hmac) {
    if (!hmac) {
      return false;
    } else if (!data || typeof data.data !== "object") {
        // I am Getting Error HERE
        console.log('Error in data', data);
        return false;
    }
    const sharedSecret = config.shopify_shared_secret;
    const calculatedSignature = crypto
      .createHmac("sha256", sharedSecret)
      .update(Buffer.from(data), "utf8")
      .digest("base64");
      console.log('calculatedsecret', calculatedSignature);

    return calculatedSignature === hmac;
  };

and the body I am getting it as undefined. suggest me how to fix this problem in shopify webhook API

1 Answer 1

7

Instead of using the bodyparser.json() use bodyparser.raw to fetch the all the payload to process the shopify webhook verification.

router.use(bodyparser.raw({ type: "application/json" }));

// Webhooks
router.post("/", async (req, res) => {
  console.log("Webhook heard!");
  // Verify
  const hmac = req.header("X-Shopify-Hmac-Sha256");
  const topic = req.header("X-Shopify-Topic");
  const shop = req.header("X-Shopify-Shop-Domain");

  const verified = verifyWebhook(req.body, hmac);

  if (!verified) {
    console.log("Failed to verify the incoming request.");
    res.status(401).send("Could not verify request.");
    return;
  }

  const data = req.body.toString();
  const payload = JSON.parse(data);
  console.log(
    `Verified webhook request. Shop: ${shop} Topic: ${topic} \n Payload: \n ${data}`
  );

  res.status(200).send("OK");
});

// Verify incoming webhook.
function verifyWebhook(payload, hmac) {
  const message = payload.toString();
  const genHash = crypto
    .createHmac("sha256", process.env.API_SECRET)
    .update(message)
    .digest("base64");
  console.log(genHash);
  return genHash === hmac;
}
Sign up to request clarification or add additional context in comments.

2 Comments

i had to use this to make it work: verifyWebhook(req.rawBody, hmac);
yes, that is correct @smoore4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.