Solved

Cannot able to validate the shopify webhook using nodejs

marclab
Visitor
2 0 0

Hi team,

I cannot able to validate the web hook response from the shopify. 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. Please sugget me how to resolve this problem

My store name is "marclab-consulting.myshopify.com"

Do let me know any if queries any!!

 

 

Accepted Solution (1)
torontotom
Visitor
2 1 3

This is an accepted solution.

I just don’t think req.rawbody is being set properly.
Use bodyparser.raw instead of .json

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: Buffer, hmac: string) {
const message = payload.toString();
const genHash = crypto
.createHmac('sha256', process.env.API_SECRET)
.update(message)
.digest('base64');
console.log(genHash);
return genHash === hmac;
}

This code works

View solution in original post

Replies 3 (3)

torontotom
Visitor
2 1 3

Can you verify you're definitely getting to the line in your app.js: 

 

req.rawbody = buf;

 

marclab
Visitor
2 0 0

Hi @torontotom ,

 

I am getting the response as below for the "req.rawbody"

body <Buffer 7b 22 69 64 22 3a 38 32 30 39 38 32 39 31 31 39 34 36 31 35 34 35 30 38 2c 22 65 6d 61 69 6c 22 3a 22 6a 6f 6e 40 64 6f 65 2e 63 61 22 2c 22 63 6c 6f ... 6451 more bytes>
torontotom
Visitor
2 1 3

This is an accepted solution.

I just don’t think req.rawbody is being set properly.
Use bodyparser.raw instead of .json

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: Buffer, hmac: string) {
const message = payload.toString();
const genHash = crypto
.createHmac('sha256', process.env.API_SECRET)
.update(message)
.digest('base64');
console.log(genHash);
return genHash === hmac;
}

This code works