-
-
Save joshbeckman/5c4f0244914adfd312e4 to your computer and use it in GitHub Desktop.
const PORT = 3000; | |
const SECRET = 'APP_SHARED_SECRET'; | |
var http = require('http'), | |
crypto = require('crypto'), | |
server; | |
function verifyShopifyHook(req) { | |
var digest = crypto.createHmac('SHA256', SECRET) | |
.update(new Buffer(req.body, 'utf8')) | |
.digest('base64'); | |
return digest === req.headers['X-Shopify-Hmac-Sha256']; | |
} | |
function parseRequestBody(req, res) { | |
req.body = ''; | |
req.on('data', function(chunk) { | |
req.body += chunk.toString('utf8'); | |
}); | |
req.on('end', function() { | |
handleRequest(req, res); | |
}); | |
} | |
function handleRequest(req, res) { | |
if (verifyShopifyHook(req)) { | |
res.writeHead(200); | |
res.end('Verified webhook'); | |
} else { | |
res.writeHead(401); | |
res.end('Unverified webhook'); | |
} | |
} | |
server = http.createServer(parseRequestBody); | |
server.listen(PORT, function(){ | |
console.log("Server listening on: http://localhost:%s", PORT); | |
}); |
It is not working for me . The generated digest and received headers are different.. @tiendq can you please elaborate how to use body-parser.text() in above code ?
more details here - https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/verify-shopify-webhook-integrity-node-express-js-512656
let jsonString = JSON.stringify(req.body)
let digest = crypto.createHmac("sha256", SECRET)
.update(jsonString, 'utf8','hex')
.digest('base64');
console.log("digest->"+digest)
I hope this will help.
@Kushan-'s solution works perfectly, while Shopify's own express middleware did not.. but they may be modifying the request somewhere... not sure, but this works.
+1 for @tiendq's solution
Somehow, using body-parser.json() blocked the processing of the request.
this.express = express()
.use(rawBodyGetter)
.use(bodyParser.text())
// .use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }))
const checkWebHookIntegrity = async (req: any, res: any, next: any) => {
let raw;
try {
raw = await rawBody(req);
const digest = crypto.createHmac('sha256', CONFIG.SHOPIFY_WEBHOOK_SECRET)
.update(raw)
.digest('base64');
if (digest === req.headers['x-shopify-hmac-sha256']) {
req.body = JSON.parse(raw.toString('utf-8'));
next();
} else {
console.log('Error with request', os.EOL, req.body);
return res.status(401).send();
}
} catch(e) {
console.log(e);
return res.status(500).send();
}
};
@Kushan- Thanks you!
I tried this. But not working. Am I doing anything wrong?
let jsonString = JSON.stringify(req.body);
const generated_hash = crypto
.createHmac('sha256', secret)
.update(jsonString,'utf8','hex')
.digest('base64');
It's been a long time i worked with shopify api, perhaps, uppercase secret
might help, what error you are getting?
thank you for your reply. tried the uppercase approach. did not work.
got this error
0|wmbi | HASH COMPARE FAILED - Unable to verify request HMAC
0|wmbi | POST /webhook/ads-hkg - - ms - -
0|wmbi | { sp_hmac: 'aAwa1U3uPwRl4fJVLmxuLkaKMiyZRnCwlHMl3q8iDxI=',
0|wmbi | sp_topic: 'orders/create',
0|wmbi | sp_shopDomain: 'ads-api-testing.myshopify.com' }
0|wmbi | HASH COMPARE FAILED - Unable to verify request HMAC
0|wmbi | generated_hash: iiKQ9W/kInYASnwL+j2oG2cjbHBFj9CqrMlyd76yaew=
0|wmbi | sp_hmac: aAwa1U3uPwRl4fJVLmxuLkaKMiyZRnCwlHMl3q8iDxI=
@andjosh great work, I don't know why Shopify documentation is so poor and it takes 2 different ways to verify HMAC.
@jmortensen and others: I got it worked well with Express and its middleware, you must use
body-parser
to getrequest.body
, the key point is get it correctly :)Use
body-parser.text()
even when Shopify sends you JSON data (application/json
).Replace line 10 with
Buffer.from(request.body)
since theconstructor
is deprecated.