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.

Verify webhook on nodejs problem

Verify webhook on nodejs problem

rdiazroman
Visitor
1 0 0

I'm unable to verify a Webhook in Node js.

 

I followed the solution proposed here but I cannot make it work:

https://community.shopify.com/c/webhooks-and-events/verify-webhook-on-nodejs/m-p/2172977/highlight/t...

 

I make sure that I use always the same SHOPIFY_WEBHOOK_SECRET.

But Received X-Shopify-Hmac-Sha256, and Calculated HMAC Hash never match. 

 

Here is the script to create the webhook:

 

import fetch from 'node-fetch';
import dotenv from 'dotenv';

// Load environment variables from .env file
dotenv.config();

const { SHOPIFY_STORE, SHOPIFY_API_KEY, SHOPIFY_API_PASSWORD, SHOPIFY_WEBHOOK_SECRET } = process.env;

// Function to create a Shopify webhook
const createShopifyWebhook = async () => {
  const url = `https://${SHOPIFY_STORE}/admin/api/2024-07/webhooks.json`;

  // Create the base64-encoded credentials for Basic Auth
  const credentials = Buffer.from(`${SHOPIFY_API_KEY}:${SHOPIFY_API_PASSWORD}`).toString('base64');  

  const webhookData = {
    webhook: {
      topic: 'orders/paid',  // The event that triggers the webhook
      address: 'https://my-heroku-www/webhook/order-paid',  // Your actual webhook URL
      format: 'json',  // Webhook payload format
      secret: SHOPIFY_WEBHOOK_SECRET  // Secret used to sign the webhook for HMAC verification
    }
  };

  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Basic ${credentials}`,  // Basic Authentication header
      },
      body: JSON.stringify(webhookData),  // Send webhook data
    });

    if (!response.ok) {
      throw new Error(`Error creating webhook: ${response.statusText}`);
    }

    const data = await response.json();
    console.log('Webhook created successfully:', data);
  } catch (error) {
    console.error('Error creating webhook:', error);
  }
};

createShopifyWebhook();

 

and here the webhook validation:

 

import express from 'express';
import bodyParser from 'body-parser';
import crypto from 'node:crypto';
import dotenv from 'dotenv';

dotenv.config();

const { SHOPIFY_WEBHOOK_SECRET } = process.env;

const app = express();
const port = process.env.PORT || 3000;

// Middleware to capture raw body for HMAC verification
app.use(bodyParser.raw({ type: 'application/json' }));

// HMAC Verification Middleware
const verifyShopifyWebhook = (req, res, next) => {
  const hmacHeader = req.headers['x-shopify-hmac-sha256'];
  
  // Generate the HMAC using the raw body
  const calculatedHmac = crypto
    .createHmac('sha256', SHOPIFY_WEBHOOK_SECRET)
    .update(req.body, 'utf8', 'hex')
    .digest('base64');
  
  console.log('Received X-Shopify-Hmac-Sha256:', hmacHeader);
  console.log('Calculated HMAC Hash:', calculatedHmac);

  const hmacBuffer = Buffer.from(hmacHeader, 'base64');
  const calculatedHmacBuffer = Buffer.from(calculatedHmac, 'base64');

  if (hmacBuffer.length !== calculatedHmacBuffer.length) {
    console.log('HMAC different lenghts');
    return res.status(401).send("Couldn't verify incoming Webhook request!");
  }

  if (!crypto.timingSafeEqual(hmacBuffer, calculatedHmacBuffer)) {
    console.log('HMAC comparison failed');  // <----------------- This is the output I get
    return res.status(401).send("Couldn't verify incoming Webhook request!");
  }
  
  console.log('Webhook verification successful');
  
  // Parse the raw body into JSON after verification
  req.body = JSON.parse(req.body.toString());
  next();  // Proceed to the next middleware or route handler
};

// Use the verification middleware before any route that needs verification
app.post('/webhook/order-paid', verifyShopifyWebhook, (req, res) => {
  // Handle the verified webhook here
  const payload = req.body;
  console.log('Webhook Payload:', payload);
  
  res.status(200).send('Webhook processed successfully');
});

// Start the server
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

I always get "HMAC comparison failed" 

 

I would need some help please, really don't know what is wrong...

 

Thank you very much

Reply 1 (1)

Kyle_liu
Shopify Partner
437 55 80

hi @rdiazroman 

 

You can try it.

const bodyParser = require('body-parser')
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())

 

const hmac = req.header("X-Shopify-Hmac-Sha256");
LOGGER.info(`hmac: ${hmac}`);

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

console.log(genHash);

if (genHash !== hmac) {
return res.status(401).send("Couldn't verify incoming Webhook request!");
}
If this is helpful, please Like and Accept the solution.
Want to modify or custom changes on store? Let me help.
- Feel free to contact me Email Me Buy Me A Coffee