Topics covering webhook creation & management, event handling, Pub/Sub, and Eventbridge, in Shopify apps.
We are looking to use Amazon's EventBridge service for pre-processing our webhooks, and I am struggling to manage the HMAC verification.
My first question would be: is it even necessary to verify webhooks in your AWS Event Bus settings? Since Shopify is a supported Partner event source maybe it can be confirmed that all events through such an Event Bus are verified by Amazon as being from Shopify. My thinking though is that the Event Bridge Rule only verifies the pattern, not the contents / sender.
If it is necessary to verify the webhooks, I am struggling to do so. My current assumption is that the raw request body is processed into JSON by the time my Lambda function handler receives it. Is there a way to access the raw request body in a Lambda function or to verify with an already parsed JSON string? Thanks in advance!
This was my attempt to verify with a Ruby Lambda function:
def lambda_handler(event:, context:)
hmac_header = event["detail"]["metadata"]["X-Shopify-HMAC"]
payload = event["detail"]["payload"]
calculated_hmac = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', ENV['SHOPIFY_CLIENT_SECRET'], JSON.generate(payload)))
if secure_compare(calculated_hmac, hmac_header)
{ statusCode: 200, body: JSON.generate(event) }
else
{ statusCode: 401, body: "Unauthorized" }
end
end
Hello, the event your receiving should be trustworthy, although as you said, the EvenBridge rule doesn't verify the sender. So though it's most likely trustworthy, it's best to verify using the HMAC in the payload as per https://shopify.dev/tutorials/manage-webhooks
I'm not entirely sure but looking at your code you may be doing an extra JSON conversion by adding JSON.generate(payload).
mrad | Developer @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog
Thank you for the feedback. I have used that guide before to verify webhooks, but my understanding is that the examples given show what you can do when able to access the raw request body before it has been processed. For example the Sinatra demo uses `request.body.read` which reads the raw body as a string. I'm unsure how to do that using EventBridge.
@mrad wrote:I'm not entirely sure but looking at your code you may be doing an extra JSON conversion by adding JSON.generate(payload).
`payload` seems to be a Ruby hash in this example and I believe `OpenSSL::HMAC.digest` requires a string input which is why I converted it to JSON. It causes an error when I do not convert the payload back into a string, but it's apparently not the same string used in the original digestion by Shopify to generate `HTTP_X_SHOPIFY_HMAC_SHA256`.
Hey @cmeurer, were you able to figure out the solution? I'm running into the same problem here with my JS Lambda function.
I was also facing this issue (Node lambda), for me the problem ended up being that my request body needed to have gid values escaped like so:
gid:\\/\\/shopify\\/<namespace>\\/<id>
In my function I was doing a JSON.parse() on the event body and then JSON.stringify()-ing the payload to send to my service, which formatted the gid values as:
gid://shopify/<namespace>/<id>
I resolved the issue by doing a .replace(/\//g, '\\/') on the payload before sending.
I'm running into this issue as well. It would be nice if a Shopify developer could provide a clear example of how we can validate the HMAC when using the AWS EventBridge integration.
I'm developing my Lambda's with Node and register for the various product update webhooks. The issue is that, as far as I can tell, there is no way to get the raw, original request body. The body available is already parsed into a JSON object.
The code below gets me close. It converts the object back into a string, replaces any HTML tag opening/closing brackets with their string unicode representation, and then double-escapes any forward slashes.
JSON.stringify(event.detail.payload)
.replace(/</g, '\\u003c')
.replace(/>/g, '\\u003e')
.replace(/\//g, '\\/');
In some cases, the above may be enough. However, for products the variant items include a weight field which is apparently treated as a float. This is a problem because if the value is zero or any whole number then the decimal portion is lost during the JSON conversion.
// raw request body
{"weight":0.0}
// JSON.stringify-ed value
{"weight":0}
There's really no way to get that back. I'm guessing prices would have the same issue. I don't know what else.
Hi,
Just wanted to provide an update to this issue.
There is no need to validate HMAC with EventBridge. Only Shopify is able to produce events into the partner event source that you would have configured in the App Setup for your app.
For anyone still doing the validation and having issues with some webhooks, we're currently trying to resolve an issue with Amazon and json encoding that in some cases causes an issue with the generated HMAC.
It's best to simply remove HMAC validation for EventBridge and Pub/Sub deliveries as these are both considered trusted delivery channels. Only HTTP webhooks require HMAC validation.
Thanks
To learn more visit the Shopify Help Center or the Community Blog.