You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Oct 6, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Oct 6, 2026. It is now read-only.
Utils::validateHmac fails if the query params contains non url-safe characters. #412
Utils::validateHmac fails if the query params contains non url-safe characters. For example, for a oauth authorization callback, if the state is a base64-encoded string, the trailing = character will make the HMAC validation fail. After talking with the Shopify support, I was told that the HMAC sent from Shopify is computed based on the original query params, instead of the URL-encoded version.
Expected behavior
HMAC validation should still work if the HMAC comes for a URL containing encoded characters
Actual behavior
Utils::validateHmac returns false, even if I can manually confirm that the HMAC is correct
Steps to reproduce the problem
Initiate an OAuth autorization request. For the state, use non url-safe characters (i.e. JSON, Base64, or colons :). In my case, I use an app I'm developping, and requesting access for that app to a test shop.
When the autorization request is accepted, the user is redirected to your redirect_uri with the resulting query parameters. Save those for next step
use Utils::validateHmac to validate the callback. It will fail if the state indeed contains encoded characters.
Reduced test case
The best way to get your bug fixed is to provide a reduced test case.
Checklist
I have described this issue in a way that is actionable (if possible)
I have a working fix, but the unit tests don't really address this problem very well, since they compute themselves a correct HMAC instead of having a literal string as an expected value.
I am wondering if you could provide me a bit more information regarding your app set up? (Example code is always helpful to understand!)
Initiate an OAuth autorization request. For the state, use non url-safe characters
This sounds like you are not using this packages OAuth::begin function, but instead you are implementing OAuth manually? If so is there a reason that you need to do this?
The $state holds some kind of information that identifies the install when the browser comes back to me with the authorization code. Without it, or with a wrong/unknown one, the code would be ignored and discarded.
From what I can read of OAuth::begin, it generates its own $state, whereas mine is an id generated long before this shopify app install link would ever be.
This link worked before because the $state was hex-encoded, but the issue became apparent when I switched to base64. For reference, the state I'm testing with currently looks like base64_encode(json_encode(['method' => 'connect', 'token' => bin2hex(random_bytes(32)), 'reason' => 'commit',], JSON_THROW_ON_ERROR))
Thanks for contributing! This package is deprecated and we're archiving this repo, so we're closing all open issues and PRs. Please use shopify-app-php instead, and open new issues there. More context: Rethinking support for PHP/Python packages
Issue summary
Utils::validateHmacfails if the query params contains non url-safe characters. For example, for a oauth authorization callback, if the state is a base64-encoded string, the trailing=character will make the HMAC validation fail. After talking with the Shopify support, I was told that the HMAC sent from Shopify is computed based on the original query params, instead of the URL-encoded version.Expected behavior
HMAC validation should still work if the HMAC comes for a URL containing encoded characters
Actual behavior
Utils::validateHmacreturnsfalse, even if I can manually confirm that the HMAC is correctSteps to reproduce the problem
state, use non url-safe characters (i.e. JSON, Base64, or colons:). In my case, I use an app I'm developping, and requesting access for that app to a test shop.redirect_uriwith the resulting query parameters. Save those for next stepUtils::validateHmacto validate the callback. It will fail if thestateindeed contains encoded characters.Reduced test case
The best way to get your bug fixed is to provide a reduced test case.
Checklist