6

I want to access a service that uses JWT authentication for its API. Generating a JWT doesn't look too difficult, it is a combination of BASE64URL encoding, and HMAC Signing. However, these things can be a finicky to get right, so I was wondering if anyone had done this in Mathematica? For instance, is it possible to use the SecuredAuthenticationKey function to do what I need?

Andy Burnett
  • 257
  • 1
  • 4

1 Answers1

6

I stole the HMAC from here https://mathematica.stackexchange.com/a/167636/72682. The header/payload/secret are the same as the ones on the Wikipedia page https://en.wikipedia.org/wiki/JSON_Web_Token. Thanks to the suggestions in @WReach's comment I was able to get the same token in the Wikipedia article.

hmacFnew[method_, message_, key_] := 
 Module[{dkey, dmsg, opad, ipad, blocksize}, 
  blocksize = If[method === "SHA384" || method === "SHA512", 128, 64];
  {dkey, dmsg} = StringToByteArray /@ {key, message};
  If[Length[dkey] > blocksize, dkey = Hash[dkey, method, "ByteArray"]];
  dkey = Normal[dkey];
  If[Length[dkey] < blocksize, dkey = PadRight[dkey, blocksize, 0]];
  {opad, ipad} = ByteArray[BitXor[dkey, ConstantArray[#, blocksize]]] & /@ {92, 54};
  Hash[Join[opad, Hash[Join[ipad, dmsg], method, "ByteArray"]], method, "Base64Encoding"]]

urlfixb64[b64_?StringQ] := StringReplace[StringSplit[b64, "="][[1]], {"+" -> "-", "/" -> "_"}]

secret = "secretkey"; header = <|"alg" -> "HS256", "typ" -> "JWT"|>; payload = <|"loggedInAs" -> "admin", "iat" -> 1422779638|>; headerJSON = ExportString[header, "JSON", "Compact" -> True]; payloadJSON = ExportString[payload, "JSON", "Compact" -> True]; header64 = DeveloperEncodeBase64[headerJSON] // urlfixb64; payload64 = DeveloperEncodeBase64[payloadJSON] // urlfixb64; signature = hmacFnew["SHA256", header64 ~~ "." ~~ payload64, secret] // urlfixb64; token = header64 ~~ "." ~~ payload64 ~~ "." ~~ signature

(* result: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI" *)

flinty
  • 25,147
  • 2
  • 20
  • 86
  • 2
    +1. You can get the exact result from the Wikipedia article if you: 1) use ExportString[..., "JSON", "Compact"->True] to suppress pretty-printing and 2) use Developer`EncodeBase64[...] instead of ExportString[..., "Base64"] to suppress newlines in the token. – WReach Jun 17 '20 at 02:27
  • Wonderful! Thank you so much for your answer. – Andy Burnett Jun 17 '20 at 16:04