I’m having some trouble verifying the HMAC parameter coming from Shopify. The code I’m using per the Shopify documentation is returning an incorrect result.
Here’s my annotated code:
import urllib
import hmac
import hashlib
qs = "hmac=96d0a58213b6aa5ca5ef6295023a90694cf21655cf301975978a9aa30e2d3e48&locale=en&protocol=https%3A%2F%2F&shop=myshopname.myshopify.com×tamp=1520883022"
Parse the querystring
params = urllib.parse.parse_qs(qs)
Extract the hmac value
value = params['hmac'][0]
Remove parameters from the querystring per documentation
del params['hmac']
del params['signature']
Recombine the parameters
new_qs = urllib.parse.urlencode(params)
Calculate the digest
h = hmac.new(SECRET.encode("utf8"), msg=new_qs.encode("utf8"), digestmod=hashlib.sha256)
Returns False
!
hmac.compare_digest(h.hexdigest(), value)
That last step should, ostensibly, return true. Every step followed here is outlined as commented in the Shopify docs.
2
Answers
At some point, recently, Shopify started including the
protocol
parameter in the querystring payload. This itself wouldn't be a problem, except for the fact that Shopify doesn't document that:
and/
are not to be URL-encoded when checking the signature. This is unexpected, given that they themselves do URL-encode these characters in the query string that is provided.To fix the issue, provide the
safe
parameter tourllib.parse.urlencode
with the value:/
(fitting, right?). The full working code looks like this:Hope this is helpful for others running into this issue!