skip to Main Content

Following this

I was getting error – Unhandled promise rejection (rejection id: 2): TypeError: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object

So I changed to

   var msg = JSON.stringify(req.rawBody);
   var digest = crypto.createHmac('sha256', APP_SHARED_SECRET)
                     .update(Buffer.from(msg,'utf8'))
                    .digest('base64');

The signature (hmac-sha256) generated is different then what I am receiving in the request header !

Any clue or pointers will be helpful.

3

Answers


  1. You would probably want to use JSON.parse, instead of JSON.stringify, to parse the message before performing any other actions.

    Login or Signup to reply.
  2. I’m dealing with a similar issue, but you want to use

    new Buffer(....) 
    
    Login or Signup to reply.
  3. For anyone still looking for a solution, this is what worked for me

    const rawBody = req.rawBody; // expressjs
    
    // omitted
    ...
    
    const digest = crypto
        .createHmac("sha256", process.env.SHOPIFY_WEBHOOK_SECRET)
        .update(data)
        .digest("base64");
    
    return crypto.timingSafeEqual(
        Buffer.from(digest, "utf8"),
        Buffer.from(req.headers["http_x_shopify_hmac_sha256"], "utf8")
    );
    

    I was using Serverless function in Vercel, hence I used the external npm package raw-body to get the correct raw body

    const rawBody = await getRawBody(req);
    

    Notes

    • The raw body is required for hmac comparison because the req.body is a parsed object and JSON.stringify messes up the original payload.
    • Comparing the hmac with crypto.timingSafeEqual, this function prevents leaking time information to the extent.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search