What's your biggest current challenge? Have your say in Community Polls along the right column.

Why is the webhook request body undefined in my server processing?

Why is the webhook request body undefined in my server processing?

lguerra10
Excursionist
14 0 10

I'm trying to debug the processing of webhooks. Shopify is firing webhooks to my server and the webhooks are received.

My problem is that webhook ctx.request.body is undefined. That means, the webhook request comes without a body and without a body I cannot compute the Sa256 to compare to the header. This is the request in the latest webbhook I got

{
     method: 'POST',
      url: '/webhook_subscriptions_update',
      header: {
      host: 'shopifykshwishlist.herokuapp.com',
      connection: 'close',
      'user-agent': 'Shopify-Captain-Hook',
      accept: '*/*',
     'accept-encoding': 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
     'content-type': 'application/json',
     'x-shopify-api-version': '2021-10',
      'x-shopify-hmac-sha256': 'MwsDd+gZNpRcpLiZu58qXzZONRgI3N0MIn0JAtxViyo=',
      'x-shopify-shop-domain': 'vue-dawn.myshopify.com',
      'x-shopify-topic': 'app_subscriptions/update',
      'x-shopify-webhook-id': '58d3174d-84d0-4104-a41a-9da342c66ae3',
     'x-request-id': '50c2920e-6e31-463f-bb01-6693b9540a78',
     'x-forwarded-for': '34.122.195.146',
     'x-forwarded-proto': 'https',
     'x-forwarded-port': '443',
     via: '1.1 vegur',
     'connect-time': '0',
     'x-request-start': '1643299376798',
     'total-route-time': '0',
     'content-length': '304'
     }
     }

All the code I have tried uses the ctx.request.body to compute the Sa256.
I have tried to use the code supplied by Shopify but it fails and says that the webhook has not been registered, although I got success registering the webhook. Also I have the mandatory webhooks registered in the App setup in the developer dashboard.

 try {
      await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
      console.log(`Webhook processed, returned status code 200`);
      
    } catch (error) {
      console.log(`Failed to process webhook: ${error}`);
    }

The above code fails.
It may be that the person reviewing my app is firing these webhooks for me to debug and that those webhooks are not like the real ones, they are missing the body.
HELP SHOPIFY!!!

Replies 6 (6)

hazaro
New Member
4 0 0

What is the error in the catch block?

 

The HMAC verification doesn't require the the response body so it shouldn't be relevant.

banned
lguerra10
Excursionist
14 0 10

Can you please give me, and everybody, the code that you are using for the verification?

 

The code that I am using is

 

let hmac = ctx.request.headers["x-shopify-hmac-sha256"]  
let calculatedHmac= crypto.createHmac("sha256", process.env.SHOPIFY_API_SECRET
.update(JSON.stringify(ctx.request.body))
.digest("base64")
if hmac=== calculatedHmac then the verification succeeds.
PLEASE GIVE YOUR CODE
 
lguerra10
Excursionist
14 0 10

If you are using the code 

 

try {
await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
}
the catch(error) always happens if the reques.body is empty and the error is webhook (the name of the webhook) is not registered. Wich is false. I have webbhooks that register with success that  produce this error if the body is empty 
hazaro
New Member
4 0 0

Looks like you're using the NodeJS library. That process method is already doing the work for you to verify the webhook so you don't need to do any hmac comparison. The library returns an error when the webhook you're receiving is not registered [0]. Have tried following the instructions to register a webhook? Once you do that, you'll be able to use the process method.

 

[0] https://github.com/Shopify/shopify-node-api/blob/main/src/webhooks/registry.ts#L435 

banned
lguerra10
Excursionist
14 0 10

I have registered the mandatory webhooks in the Dashboard on setting up the app and the 

webhook_subscriptions_update using the method to register in the server code getting success in the registration:
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhook_subscriptions_update",
topic: "APP_SUBSCRIPTIONS_UPDATE",
webhookHandler: async (topic, shop, body) =>
ACTIVE_SHOPIFY_SHOPS[shop] = scope,
});
Of course I register in code the  APP_UNINSTALLED getting success in the registration as well as the APP_SUBSCRIPTIONS_UPDATE getting success. 
 
I thought that the
await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
 would do the job of handling the webhook but it is not doing it, giving me always the error webhook not registered, this happens for the mandatory webhooks: /shopredact /customerredact and /customerdata, which are registered thru the Dashboard as mandated by Shopify,  I tried to register the mandatory webhooks in code but i was getting Failed to register.

Because of the errors in the handling of the registration I decided that I had to try the route of calculating myself the hmac and comparing it, without success, so far.

It is bad that me and a others are wasting so much time and ansiety about this webhook deal.

Thanks for your help 
lguerra10
Excursionist
14 0 10

I got it right finally.

The request.body was empty because I forgot to pass  bodyParser() in the webhook. it should look like this: router.post("/shopredact", bodyParser(),async (ctx) =>

 

The calculation of the hmac is necessary for the mandatory webhooks that are not handled properly by the await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);

 

Once you use the bodyParser()  in the router.post receiving the webhook you can get the body of the webhook that in reality is not empty.

 

The code for the calculation of the hmac that works for me is as follows:

 

import crypto from "crypto";
let generateHash = crypto
.createHmac("sha256", process.env.SHOPIFY_API_SECRET)
.update(JSON.stringify(ctx.request.body))
.digest("base64");
 
This code generates the proper hash to compare to the hmac and everything works.
 
Thanks for the help.