webhook verification

Highlighted
New Member
4 0 0

I am working on verifying a webhook from shopify sent to an AWS endpoint and triggering a lambda function written in python 3.

 

I created the webhook in the notifications section of my shopify dashboard, and I am using the key that is available there as my SECRET variable. This is my verification function:

 

import hmac
import hashlib
import base64

def verify_webhook(data, hmac_header):
digest = hmac.new(SECRET.encode('utf-8'), data.encode('utf-8'), hashlib.sha256).digest() computed_hmac = base64.b64encode(digest) return hmac.compare_digest(computed_hmac, hmac_header.encode('utf-8'))

and my lambda handler function:

import json
import verify_webhook

def lambda_handler(event, context): data = json.dumps(event) hmac_header = event['headers']['X-Shopify-Hmac-Sha256'] verified = verify_webhook.verify_webhook(data, hmac_header) print ('verified: ',verified)

My computed hmac and the provided header are consistently different from one another. I suspect that my data variable is incorrect, but I cant put my finger on the problem. Thanks in advance for any suggestions; your help is much appreciated!

 

0 Likes
Highlighted

Give you thumbs up for building in AWS Lambda. I stumbled upon this post have a read I believe it could help you as this is something specific to Lambda.

 

https://forums.aws.amazon.com/thread.jspa?threadID=228067 

 

{
  "json" : $input.json('$'),
  "rawBody" : "$util.escapeJavaScript($input.body)"
}

 

-Sam

Achieveapplabs.com | Shopify Development | hello@achieveapplabs.com
0 Likes
Highlighted
Tourist
5 0 2

Hi guys,

 

Did anyone happen to get this working? I am trying to create a webhook and have it post to an AWS Lambda function via API Gateway ( same issue as above ), the HMAC will not validate.  I was hoping someone had a code snippet or github of a working function to validate the webhook data sent from Shopify.

 

Thanks!

Alex

0 Likes
New Member
4 0 0

Hi Alex,

 

No, I'm still stuck. I think Sam is on the right track though. I am able to get the raw body, but can't figure out the full request. If you come across any other resources I'd love to see them though.

 

Thanks,

Cyrus

0 Likes
Highlighted
New Member
4 0 0

Thanks Sam,

 

I think this is the right idea, but I cant figure out how to return the full request. All of the resources for github validation just need to raw body, and I'm having trouble translating those examples. If you come across anything else please share!

 

Thanks again for your help,

Cyrus

0 Likes
Highlighted
Tourist
5 0 2

I FINALLY got this HUGE pain in the ass to work tonight.  I am attempting to show the steps here, I will also post some links to items that helped me. 

 

In AWS > API Gateway, you have to create a Mapping Template, to intercept the incoming webhook from Shopify, then parse out the "raw body" vs the "JSON body", API Gateway will natively convert the webhook to JSON, when it does, it messes up the raw body and adds several things, this throws off your HMAC check. 

 

1.  Set up or create a Lambda Function and tie to to an API Gateway REST API ( not HTTP Passthrough ).  Map the new REST API to a POST method.  Once you are done you should have something that looks like this ( your name will differ ).

 

API Gateway Config 1.png

 

2.  Click on "POST" method under your new resource.

 

3.  In the POST method, you set Integration type to Lambda Function.  Leave the rest as default, scroll down to the bottom of the page.

 

API Gateway 2.png

 

4.  Under the Mapping Template, click the top radio button, then paste in the template I am supplying below ( this template parses out the HTTP POST Header, Body, RAW BODY, HTTP Parameters, and Query strings into seperate variables that you can consume inside your Lambda Functions.

 

API Gateway Config 3.png

 

5.  The complete script is below:

{
"body" : $input.json('$'),
"rawbody": "$util.escapeJavaScript($input.body)",
"headers": {
#foreach($header in $input.params().header.keySet())
"$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end

#end
},
"method": "$context.httpMethod",
"params": {
#foreach($param in $input.params().path.keySet())
"$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end

#end
},
"query": {
#foreach($queryParam in $input.params().querystring.keySet())
"$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end

#end
}
}

 

6.  Make SURE you Save, then click Actions > Deploy API ( I goofed and forgot to redeploy the API after making changes my first go around ). 

 

7.  Head to your Lambda function.   I am showing how to access the various variables here:

 

import json
import hmac
import hashlib
import base64

#Shopify Secret Secret Key used for verification
SECRET = 'ENTER YOUR SECRET KEY THAT SHOPIFY DISPLAYS BESIDE YOUR WEBHOOK'


def verify_webhook(data, hmac_header):
digest = hmac.new(SECRET.encode('utf-8'), data.encode('utf-8'), hashlib.sha256).digest()
computed_hmac = base64.b64encode(digest)
return hmac.compare_digest(computed_hmac, hmac_header.encode('utf-8'))

def lambda_handler(event, context):

print('Entering into the Lambda Function now.')
print('......................................')
print('The JSON body received from the API Gateway after passing through the mapping template is: ')
print(json.dumps(event))
print('The RAW body received from the API Gateway after passing through the mapping template is: ')
print(event['rawbody'])
print('The Header is: ')
print(event['headers'])
print('The Headers Shopify X-Shopify-Hmac-Sha256 signature is: ')
print(event['headers']['X-Shopify-Hmac-Sha256'])
print('Completed the printout of the passed in values.')

rawbodydata = event['rawbody']
hmac_header = event['headers']['X-Shopify-Hmac-Sha256']

verified = verify_webhook(rawbodydata, hmac_header)

if not verified:
print('Did not pass Shopify HMAC validation!')
return {
'statusCode': 401,
'body': json.dumps('Did not pass Shopify HMAC validation!')
}


if verified:
print('OOOOOHHH YEAH!!! Passed Shopify HMAC validation!')
#
# YOUR APP LOGIC GOES HERE!!!!
#
return {
'statusCode': 200,
'body': json.dumps('OOOOOHHH YEAH!!! Passed Shopify HMAC validation!')
}

 

 

I am going to continue working on this to parse out the variables/data I need.  I'm willing to barter with anyone if they are interested?? I am not a programmer by trade, this was just me being persistant and knowing a bit about networking/HTTP Requests and a LOT of screwing around with AWS API Gateway.  I did find a VERY good Youtube series on API Gateway here:

 

His Really good video's start from about video 20 and go up to 38.  These cover all the basics of API Gateway.

https://www.youtube.com/watch?v=K1E8UM6IdNY&list=UUKdYWKHTqJdJs4yQb0M7o3Q

 

https://www.youtube.com/watch?v=2Z-Utw_xl4c

https://kennbrodhagen.net/2015/12/06/how-to-create-a-request-object-for-your-lambda-event-from-api-g...

 

Hope that helps someone out....

 

Alex

1 Like
Highlighted
Tourist
5 0 2

One last thing... if you want to see the actual values real time, look at the CloudWatch logs as you execute your webhook from Shopify, that was how I was troubleshooting.  You could also use PostMan and emulate a Shopify webhook post. 

0 Likes
Highlighted

@AlexH316  that is damn good work! Kudos to you. Frankly using API Gateway and Lamda functions is way cool.

 

All the best,

 

Sam

Achieveapplabs.com | Shopify Development | hello@achieveapplabs.com
0 Likes
Highlighted
Tourist
5 0 2

Sam,

 

Thank you for kind words.  Quick question, I noticed your website for achieveapplabs.com, you guys do Shopify theme development?  Do you happen to have any example sites I could take a look at?  I may have an opp for you.

 

Thanks!

Alex

1 Like
Highlighted

Hi @AlexH316 ,

 

We haven't ventured into Shopify themes yet, but we know we will eventually. Our focus is on app development at the moment. 

 

Regards,

 

Sam

Achieveapplabs.com | Shopify Development | hello@achieveapplabs.com
0 Likes