0

I am trying to implement Shopify's JWT cookieless authentication using Apps Script: https://shopify.dev/tutorials/authenticate-your-app-using-session-tokens#verify-the-signature

When I do this:

var byteSignature = Utilities.computeHmacSha256Signature(<header>.<payload>, 'sshhh');
var signed = Utilities.base64EncodeWebSafe(byteSignature);

signed equals the <signature> from the JWT, except signed has an extra = buffer character at the end. Am I doing something wrong here, or do I just strip it of any = characters at the end for the purposes of my comparison boolean? Is there a better way?

I am basing this in part off of the npm library: https://github.com/leighs-hammer/shopify-jwt-auth-verify/blob/master/src/index.ts

TheMaster
  • 45,448
  • 6
  • 62
  • 85
policenauts
  • 512
  • 6
  • 18
  • 1
    I believe it shouldn't matter. See duplicate answers – TheMaster Oct 09 '20 at 03:27
  • 2
    I'm not really clear about the used `base64EncodeWebSafe` method, but what you need for JWT is Base64Url encoding, see also my [answer here](https://stackoverflow.com/questions/64013743/jwt-hs512-signature-slightly-different-from-jwt-io-if-calculated-with-python/64013839#64013839) – jps Oct 09 '20 at 10:15
  • Thanks all, I'll just go ahead and do that. – policenauts Oct 09 '20 at 16:14
  • @jps I checked other sources. It seems padding is "optional" and not needed to be removed. Policenauts, Try it without removing padding. If it doesn't work, remove it. – TheMaster Oct 09 '20 at 16:21
  • Thanks @TheMaster, if I don't .replace the ```=``` sign, I get equals is false on my boolean comparison to the original JWT signature. Dropping it seems to be working so I'll just proceed with that. – policenauts Oct 09 '20 at 16:33
  • actually you're verifying an existing token by comparing the given signature with the calculated signature, right? So if you do it based on the encoded signature (string comparison), the padding makes of course a difference. If you do it based on decoded signatures (byte array), the padding in not relevant. But instead of doing it manually, you might also use an existing JWT framwork. Check the [list of libraries](https://jwt.io/#libraries-io) to find something suitable. – jps Oct 09 '20 at 16:38
  • @policenauts Of course it'll be false on direct string comparison. But shopify might/will still accept the jwt. See whether it accepts the token. – TheMaster Oct 09 '20 at 17:06
  • Thanks both, in this case Shopify puts the JWT verification on the part of the app developer (us). @jps I can't use a library since this part of my server is on Apps Script and there doesn't appear to be a published library for JWT there. Leaving the signature decoded using the secret as a byte array (without converting it back to string) and comparing that to the with base64 decoding shows they are identical, but one is an array [] and the other is just byte values separated by commas. Is there an easy / clean way to compare this? – policenauts Oct 09 '20 at 19:35
  • Similarly, if I base64decodewebsafe() and then base64encodewebsafe() the original , it also pads it with an = sign at the end and then the strings become identical. I suppose that's another way I could do the comparison - but I think at this point I'm inclined to use fewer lines of code and just .replace() the = sign to make the strings match. – policenauts Oct 09 '20 at 19:36
  • Please disregard the earlier statement about [] vs. raw byte values, the byte arrays are identical and pass as true when I compare using this: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript. @jps Is comparing the byte arrays better than leaving the original as a string and then removing any ```=``` sign from the calculated, base 64 re-encoded signature? – policenauts Oct 09 '20 at 19:53
  • Officially recommended Oauth library supports jwt creation. It also uses [websafe underneath](https://github.com/gsuitedevs/apps-script-oauth2/blob/master/src/Service.js#L691-L734) – TheMaster Oct 09 '20 at 20:06
  • @policenauts whether you compare based on the encoded string or the decoded byte value should not matter. – jps Oct 10 '20 at 10:36

0 Answers0