Out now! Check out the Poll results: Do you have a Shopify store?
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.

Webhook validation in Javascript/NodeJS

Webhook validation in Javascript/NodeJS

Leandro_Soler
Tourist
16 0 2

Hi,

Does anybody knows how to validate a webhook in Javascript?

I'm not sure if what it is being encoded its the request body as string or how. This is the code I have so far:

const digest = crypto
    .createHmac('SHA256', sharedSecret)
    .update(data)
    .digest('base64');
console.info('isSameDigest', digest, hmac);
return digest === hmac;

"data" in this case its request.body

Thanks

Replies 10 (10)

Busfox
Shopify Staff (Retired)
628 49 110

Hi Leandro,

Are you saving data as a utf-8 encoded string? It looks like other people have had success this way. Let me know if you continue to have trouble.

To learn more visit the Shopify Help Center or the Community Blog.

p1016
Visitor
2 0 1

Hello:

 

This is the NodeJs that I am using to validate the webhook, and it is not working.  Can you provide any direction?

Thank you in advance.

 

const express = require('express')
const app = express()
const getRawBody = require('raw-body')
const crypto = require('crypto')
const bodyParser = require('body-parser');
const secretKey = 'SECRET KEY'

 

exports.webhookChecker = (req, res) => {
const webhook_hmac = req.get('X-Shopify-Hmac-SHA256')

 

// Create a hash using the body and our key
const hash = crypto
.createHmac('sha256', secretKey)
.update(JSON.stringify(req.body))
.digest('base64')

// Compare our hash to Shopify's hash
if (hash === webhook_hmac) {
// It's a match! All good
console.log('Webhook came from Shopify!');
res.sendStatus(200)
} else {
// No match! This request didn't originate from Shopify
console.log('Danger! Not from Shopify!')
res.sendStatus(403)
}
}

KarlOffenberger
Shopify Partner
1873 184 903

Try with

 

.update(JSON.stringify(req.body), 'utf8')

and also, doing a regular equality check isn't recommended as it leaves you vulnerable to timing attacks. Prefer to use safe-compare when checking the 2 hashes.

 

Looks okay otherwise.

p1016
Visitor
2 0 1

Thank you Karl.  I tried that, and it is still not working.  I have verified that I am using the correct secret key, I still can't validate the test webhook.  I will implement the safe-compare before I go live, thank you for the suggestion.  

 

The Ruby and PHP examples reference $data, and I am assuming that the this is just what is returned by req.body.  Is there anywhere, that you know of, that I can see exactly what I should be hashing?

KarlOffenberger
Shopify Partner
1873 184 903

Check koa webhook middleware or express equivalent etc. Quite a few of these out in the wild.

Conner_Pope
Shopify Partner
48 1 19

I can confirm that I'm getting the same error, I have similar code in my program:

 

verifyHmac(data, hmac) {
if (!hmac) {
return false;
} else if (!data) {
return false;
}
const calculatedSignature = crypto.createHmac('sha256', config.sharedSecret).update(data, 'utf8').digest('base64');
return calculatedSignature === hmac;
},

however, it still doesn't work. Any help 🙂

wb1
Shopify Partner
64 2 17

You need to use the following. You can validate this by generating a hash in liquid then validating with your function.

<script>
    {% assign my_secret_string = "no can defense the darce" | hmac_sha256: "protect ya neck fool" %}
    console.log('sha256 {{my_secret_string}}')
  </script>

 

function compare_sha256 (inbound_hmac, secret, str) => {
  console.log('secret, str', secret, str)
  var my_hmac = crypto.createHmac('sha256', secret).update(str).digest('hex')
  console.log('inbound_hmac', inbound_hmac, 'my_hmac', my_hmac)
  return inbound_hmac === my_hmac ? true : false
}

 

jsingh
Shopify Partner
4 0 0
    let fnHash = resHeaders["x-shopify-hmac-sha256"];
    let fnBody = JSON.stringify(data.body);
    let secretKey = ""; //  All your webhooks will be signed with 0f009e8f22886da5b5cde06cb34bd7e411c9c1b06519a92800bd303f7188 so you can verify their integrity.
    let finalHash = crypto
        .createHmac('sha256', secretKey)
        .update(fnBody, 'utf8')
        .digest('base64');
    log.info( finalHash, "!-----==========-----", fnHash);

my hash code also not matching for nodejs
Can someone guide me, Am I missing something @Busfox @KarlOffenberger 

Helios
Visitor
1 0 1

This one works for me, using express:

// Enable JSON use
app.use(bodyParser.json({
  verify: (req, res, buf) => {
    req.rawBody = buf;
  },
}));

 

Then when compairing:

 const hash = crypto.createHmac('sha256', SHOPIFY_APP_SECRET)
    .update(Buffer.from(req.rawBody, 'utf8'))
    .digest('base64');

 

laams
Visitor
1 0 0

I am also stuck on this, and I tried the suggestions above with no luck. It would be great to have a Javascript example in this page - https://shopify.dev/tutorials/manage-webhooks#verify-webhook