Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Re: verify webhook on nodejs

Solved

verify webhook on nodejs

Harelk1015
Shopify Partner
40 1 6

Hey :),

im trying to veryfiy webhooks in my nodejs app. but it just doesnt work, here is my code : 

app.use(shopify.config.webhooks.path, async (req, res, next) => {
  if (!req.body) {
    return res.status(401).send("Couldn't verify incomming Webhook request!");
  }
  const hmac = req.headers["x-shopify-hmac-sha256"];

  const genHash = crypto
    .createHmac("sha256", process.env.SHOPIFY_API_SECRET)
    .update(JSON.stringify(req.body), "utf8", "hex")
    .digest("base64");

  console.log(hmac);
  console.log(genHash);

  if (genHash !== hmac) {
    return res.status(401).send("Couldn't verify incomming Webhook request!");
  }

  next();
});


Please help meee

Accepted Solution (1)

Liam
Community Manager
3108 342 884

This is an accepted solution.

Hi Harelk1015,

 

Your code seems to be on the right track for verifying Shopify webhooks in a Node.js app. However, there are a few common pitfalls and nuances to be aware of:

1. Raw Body Parsing: Shopify's HMAC verification requires the raw request body. If you're using a body parser middleware like express.json(), it will parse the body before your webhook verification code gets to it. You need to capture the raw body before it's parsed.

2. Buffered Raw Body: Instead of using JSON.stringify(req.body), you should use the raw buffered body for the HMAC calculation.

3. Middleware Order: Ensure that your webhook verification middleware is placed before any body parsing middleware in your Express app.

Here's a revised version of your code, capturing the raw body and using it for verification:

const bodyParser = require('body-parser');

// Middleware to capture raw body
app.use(shopify.config.webhooks.path, bodyParser.raw({ type: 'application/json' }), async (req, res, next) => {
const hmac = req.headers["x-shopify-hmac-sha256"];

const genHash = crypto
.createHmac("sha256", process.env.SHOPIFY_API_SECRET)
.update(req.body, "utf8", "hex")
.digest("base64");

console.log(hmac);
console.log(genHash);

if (genHash !== hmac) {
return res.status(401).send("Couldn't verify incoming Webhook request!");
}

// Now, if you want to use the parsed body later in your app, you can parse it here:
req.body = JSON.parse(req.body);

next();
});

Hope this helps!

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

View solution in original post

Replies 10 (10)

Liam
Community Manager
3108 342 884

This is an accepted solution.

Hi Harelk1015,

 

Your code seems to be on the right track for verifying Shopify webhooks in a Node.js app. However, there are a few common pitfalls and nuances to be aware of:

1. Raw Body Parsing: Shopify's HMAC verification requires the raw request body. If you're using a body parser middleware like express.json(), it will parse the body before your webhook verification code gets to it. You need to capture the raw body before it's parsed.

2. Buffered Raw Body: Instead of using JSON.stringify(req.body), you should use the raw buffered body for the HMAC calculation.

3. Middleware Order: Ensure that your webhook verification middleware is placed before any body parsing middleware in your Express app.

Here's a revised version of your code, capturing the raw body and using it for verification:

const bodyParser = require('body-parser');

// Middleware to capture raw body
app.use(shopify.config.webhooks.path, bodyParser.raw({ type: 'application/json' }), async (req, res, next) => {
const hmac = req.headers["x-shopify-hmac-sha256"];

const genHash = crypto
.createHmac("sha256", process.env.SHOPIFY_API_SECRET)
.update(req.body, "utf8", "hex")
.digest("base64");

console.log(hmac);
console.log(genHash);

if (genHash !== hmac) {
return res.status(401).send("Couldn't verify incoming Webhook request!");
}

// Now, if you want to use the parsed body later in your app, you can parse it here:
req.body = JSON.parse(req.body);

next();
});

Hope this helps!

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Harelk1015
Shopify Partner
40 1 6

OMG, thanks so much ahahahhaha.
finally the recived hmac and the one that im generating matching! i love it thank you a lot!

Harelk1015
Shopify Partner
40 1 6

I do still see this in the console, that does that mean ? 

2023-08-08 15:32:50 │ backend │ [shopify-api/INFO] Receiving webhook request
2023-08-08 15:32:50 │ backend │ [shopify-app/ERROR] Failed to process webhook: Error: No body was received when processing webhook

Sidekikk
Tourist
8 0 1

hi, this code works to get the raw body. But still the generated hash and the one in the header doesnt match. The secret key is fetched from the "API Credentails -> API secret key"?

 
Harelk1015
Shopify Partner
40 1 6

You are right, they really dont match, did you solve it ?? 😞

samir_al_anabi
Shopify Partner
8 3 0

Yes i'm also stuck on verification of hmac

Harelk1015
Shopify Partner
40 1 6

did you solve maybe ?

aldoalprak
Shopify Partner
19 1 1

Failed to process webhook: Error: No body was received when processing webhook --> this error happens because you parse the object instead of string. 

 

At the end of solution, there is a line of code to parse the JSON, my guess is you parse the JSON twice because I did it before. You should delete that row and it should solve the error. I attached the code that I mentioned.

thaitv91
New Member
4 0 0
SHOPIFY_API_SECRET: from API  key and secret key. But they not match 
 
this.app.use(
      '/api/v1/shopify-webhook',
      bodyParser.raw({ type: 'application/json' }),
      new SfOrderFromShopifyRoutes().router
    );

const hmac = _.get(req, 'headers.x-shopify-hmac-sha256', '');

    const topic = _.get(req, 'headers.x-shopify-topic', '');
    const shop = _.get(req, 'headers.x-shopify-shop-domain', '');

 

    const genHash = crypto.createHmac('sha256', SHOPIFY_API_SECRET).update(_.get(req, 'body'), 'utf8').digest('base64');
thaitv91
New Member
4 0 0

I applied your code. But when I compare hmac from header and general hash from SHOPIFY_API_SECRET (From API key and secret key), they really not match