Amazon EventBridge Webhook Verification

cmeurer
Shopify Partner
5 0 0

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

 

0 Likes
marcusradica
Shopify Staff
Shopify Staff
33 3 4

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).

marcusradica | 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

0 Likes
cmeurer
Shopify Partner
5 0 0

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.


@marcusradica 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`. 

0 Likes
jaysbays
New Member
1 0 0

Hey @cmeurer, were you able to figure out the solution? I'm running into the same problem here with my JS Lambda function.

0 Likes
sgfault
New Member
1 0 1

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.