I'm trying to validate the Shopify HMAC during an OAUTH request and the hash I generate does not match the one provided as part of the request.
I've found some other threads but they are either outdated, as the documentation now states it uses a GET request instead of POST, or unanswered in java.
My C# code is as follows:
string key = "mysecretkey";
string message = string.Format("shop={0}×tamp={1}", shop, timestamp);
System.Text.ASCIIEncoding encoding = new ASCIIEncoding();
byte[] keyBytes = encoding.GetBytes(key);
byte[] messageBytes = encoding.GetBytes(message);
System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
byte[] bytes = cryptographer.ComputeHash(messageBytes);
string digest = BitConverter.ToString(bytes).Replace("-", "");
bool valid = digest == hmac.ToUpper();
I'm guessing the message is being built incorrectly but I've followed the official documentation with no luck.
Can someone help please?
OK the devs at Shopify got back to me with the answer. It seems you need to hash the entire contents of the querystring in alphabetical order except the signature and hmac. I had my own parameter (rlr) I was appending as well as one not mentioned in the docs (state).
string message = "";// "code=7af66fd73427a1634cee3103297230b8&rlr=9DFD5EA9-7747-4142-97D9-2D44BBA442F1&shop=appswiz.myshopify.com&state=fa992b8f-762e-4813-b707-6044e71ad3b5×tamp=1448856806";
message = "code=xxxxxxxx";
message += "&rlr=xxxxx";
message += "&shop=xxx.myshopify.com";
message += "&state=xxxxxxxx";
message += "×tamp=1449111190";
hmac = "xxxxxxx";
System.Text.ASCIIEncoding encoding = new ASCIIEncoding();
byte[] keyBytes = encoding.GetBytes(key);
byte[] messageBytes = encoding.GetBytes(message);
System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
byte[] bytes = cryptographer.ComputeHash(messageBytes);
string digest = BitConverter.ToString(bytes).Replace("-", "");
return digest == hmac.ToUpper();
This now works.
You are calculating a HMAC without using your key.
The documentation states that you should generate the HMAC digest using the shared key. What is the meaning of an HMAC value without the key anyways? Anybody could mimic the shopify server if Shopify had not use the pre-shared key between you and them for calculating the HMAC.
The following code block is from the documentation:
digest = OpenSSL::Digest.new('sha256')
secret = "hush"
message = "shop=some-shop.myshopify.com×tamp=1337178173"
digest = OpenSSL::HMAC.hexdigest(digest, secret, message)
digest == "2cb1a277650a659f1b11e92a4a64275b128e037f2c3390e3c8fd2d8721dac9e2"
Therefore, try cryptographer.Key = keyBytes; before computing the Hash
byte[] keyBytes = encoding.GetBytes(key);
byte[] messageBytes = encoding.GetBytes(message);
System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
cryptographer.Key = keyBytes;
byte[] bytes = cryptographer.ComputeHash(messageBytes);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With