Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shopify C# HMAC SHA256 OAuth Validation

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}&timestamp={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?

like image 259
Guy Lowe Avatar asked Nov 21 '25 08:11

Guy Lowe


2 Answers

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&timestamp=1448856806";
        message = "code=xxxxxxxx";
        message += "&rlr=xxxxx";
        message += "&shop=xxx.myshopify.com";
        message += "&state=xxxxxxxx";
        message += "&timestamp=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.

like image 166
Guy Lowe Avatar answered Nov 23 '25 22:11

Guy Lowe


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&timestamp=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);
like image 25
Oguz Ozgul Avatar answered Nov 23 '25 23:11

Oguz Ozgul



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!