Webhook Validation with Node / Express.js

Nico4
Shopify Expert
15 0 3

Having a hard time validating the Webhook with node js (using express.js)

My middleware before handling the request with a typical express router.

app.use('/webhook', 
	bodyParser.json({
		limit: '50mb',
		verify: function(req, res, buf) {
			req.rawbody = buf;
		}
	}), 
routes.webhook
);

The payload seems to be received properly with valid headers and payload, But something might be wrong in the validation code.


const message = JSON.stringify(req.rawbody);
const digest = crypto.createHmac('SHA256', config.getShopifySecretKey())
	.update(message)
	.digest('base64');
	
return callback(digest === req.headers['X-Shopify-Hmac-Sha256']);

Any help would be greatly appreciated!

0 Likes
Nico4
Shopify Expert
15 0 3

Anyone?

0 Likes
Jonathan_H
Shopify Partner
15 0 5

I'm also having this issue, my latest search is this gist

https://gist.github.com/andjosh/5c4f0244914adfd312e4

If I'm reading it right is says to use bodyParser to read the body as text rather than application/json -I guess that is what you are doing with the rawbody read???

0 Likes
Jamie_D_
Shopify Staff (Retired)
Shopify Staff (Retired)
531 1 99

You can find a working implementation here, in shopify-express

0 Likes
Jonathan_H
Shopify Partner
15 0 5

I'm a bit lost with this - I'vetried getting the hmac using the req body in a node session using the commands as outlined but can't figure out how the req body gets converted to rawdata?

I also tried using https://www.npmjs.com/package/express-shopify-webhooks but it just keeps giving me 403 errors

Is there a document showing how shopify generates the hmac? why is is done differently from the OAuth hmac ? 

0 Likes
Jonathan_H
Shopify Partner
15 0 5

I got it working for my app. Here is a summary of the actions I took:

In my main app.js I add the raw body to the req with bodyparser.json for any route that starts with '/webhooks'

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


then in my routes file I'm adding a validation function to the webhooks/app/uninstalled route:

router.post('/webhooks/app/uninstalled',validateWebhook, appcontroller.uninstalled);

This is the function that performs the validation, if the calculated hmac matches what is sent in the header then the next() function is called, otherwise send a forbidden status 403 

function validateWebhook (req,res,next){
    generated_hash = crypto
        .createHmac('sha256', config.SHOPIFY_SHARED_SECRET)
        .update(Buffer.from(req.rawbody))
        .digest('base64');
    if (generated_hash == req.headers['x-shopify-hmac-sha256']) {
        next()
    } else {
        res.sendStatus(403)
    }
}

 

Priti
Tourist
5 0 1

doesn't work ! 

const rawBody = await getRawBody(request); return { BadRequestError: request aborted...

what is shopify requirement  with request.body ??? Can you share a sample request 

0 Likes
VinayIndoria
New Member
4 0 0

Thanks
Jonathan H your code worked for me!

0 Likes
mariojuano
New Member
3 0 0

thank you @Jonathan_H  your code works perfect!

0 Likes
jgok
New Member
2 0 0

Do you have this working with HapiJs ? I'm stucked for the last two days with it. Here's what I have now:

  newOrder: {
    payload: {
      output: 'data',
      parse: false
    },
    pre: [
      {
        method: (request, reply) => {
          const hmac = request.headers['x-shopify-hmac-sha256'];
          let generatedHash = crypto.createHmac('sha256', utils.SHOPIFY_API_SECRET)
            .update(request.payload.toString())
            .digest('base64');

          if (generatedHash == request.headers['x-shopify-hmac-sha256']) {
            console.log("VALIDATED")
          } else {
            console.log("ALWAYS ENTERS HERE")
          }
        }
      }
    ],
    handler: function(request, reply) {
      reply().code(200);
    },
    auth: false,
    notes: 'Shopifys new order webhook',
    tags: ['api'],
    id: 'newOrder'
  }

HapiJs version is 14.0.0

0 Likes