9

I'm working on a Wolfram Language Package to connect into Google Bigquery (that I'll make public available). In order to finish It, I need to solve a last step, that is how to get an authentication token using JWT json file.

The package is working, but It's using R Script to generate the access token to be used in the Google Cloud API. Here the R code:

library(jsonlite)
library(httr)

authPath <- "/Users/rodrigomurta/Desktop/GetBigQueryToken/bigquery.json"

googleEndpoint <- httr::oauth_endpoint( base_url = "https://accounts.google.com/o/oauth2", authorize = "auth", access = "token", validate = "https://www.googleapis.com/oauth2/v1/tokeninfo", revoke = "revoke" )

jsonInfo <- jsonlite::fromJSON(authPath, simplifyVector = FALSE)

scope <- c( "https://www.googleapis.com/auth/bigquery", "https://www.googleapis.com/auth/cloud-platform" ) token <- httr::oauth_service_token(endpoint = googleEndpoint, secrets = jsonInfo, scope = scope) token <- token$credentials$access_token

cat(token)

The returned token is something in this format:

ya29.c.KpEB4Af1KOjCjy-msEN42XFq0IqS2DGwDG85W_Rx9WXEF_W_vGGCnG0lklw7NU25UABnWjTkwB8_NdoDsRhHHyaBLC04Cgu2mKrJ-eLQ9qlWNkwOTlpIwFCOTc-Jj1QcHzMI4JwS-nC03MeIJIC75A8bIqAEKZx90SCseNYSAKjEKw30Dbnc6Oc2k8WYwlccDlJlIQ

I tried to explore SecuredAuthenticationKey function, but without success. It would be cool to have a 100% Mathematica implementation for both facilitate distribution and make possible to run It inside Wolfram Cloud.

Some clue on how to do that?

Related:

Murta
  • 26,275
  • 6
  • 76
  • 166

1 Answers1

6

Google Cloud Platform uses the RS256 algorithm to send JWT and retrieve the tokens, all that is needed is to make a function that builds the JWT and creates a signature using GenerateDigitalSignature[].

FixB64[str_?StringQ] := StringReplace[StringSplit[str, "="][[1]], {"+" -> "-", "/" -> "_"}];

EncodeBase64[str_?StringQ] := FixB64[Developer`EncodeBase64[str]];

JWTError::InvalidJWT = "``";

GetBigQueryToken[path_] := Module[{jsonkey, jhead, jreq, pkey, encrypted, url, res},

PrintTemporary[&quot;Retrieving Token &quot;, ProgressIndicator[Appearance -&gt; &quot;Percolate&quot;]];

(* Step 1: Open JSON File. *)
jsonkey = Association[Import[path, &quot;JSON&quot;]];

(* Step 2: Build &quot;Header&quot; JSON. *)
jhead = EncodeBase64[ExportString[&lt;|&quot;alg&quot; -&gt; &quot;RS256&quot;, &quot;typ&quot; -&gt; &quot;JWT&quot;|&gt;, &quot;JSON&quot;, &quot;Compact&quot; -&gt; True]];

(* Step 3: Build &quot;Payload&quot; JSON. *)
jreq = EncodeBase64[StringReplace[ExportString[&lt;|&quot;iss&quot; -&gt; StringTrim[jsonkey[[&quot;client_email&quot;]]], &quot;scope&quot; -&gt; &quot;https://www.googleapis.com/auth/bigquery&quot;, &quot;aud&quot; -&gt; &quot;https://oauth2.googleapis.com/token&quot;, &quot;iat&quot; -&gt; UnixTime[], &quot;exp&quot; -&gt; UnixTime[] + 3600|&gt;, &quot;JSON&quot;, &quot;Compact&quot; -&gt; True], &quot;\\&quot; -&gt; &quot;&quot;]];

(* Step 4: Open PrivateKey and Encrypt &quot;Header&quot; and &quot;Payload&quot; together. *)
pkey = First[ImportString[StringTrim[jsonkey[[&quot;private_key&quot;]]], &quot;PEM&quot;]];
encrypted = FixB64[BaseEncode[GenerateDigitalSignature[jhead ~~ &quot;.&quot; ~~ jreq, pkey][[1, -1]]]];

(* Step 5: Build the URL. *)
url = HTTPRequest[&lt;|&quot;Scheme&quot; -&gt; &quot;https&quot;, &quot;Domain&quot; -&gt; &quot;oauth2.googleapis.com&quot;, &quot;Path&quot; -&gt; &quot;token&quot;, &quot;Method&quot; -&gt; &quot;POST&quot;, &quot;ContentType&quot; -&gt; &quot;application/x-www-form-urlencoded&quot;, &quot;Query&quot; -&gt; {&quot;grant_type&quot; -&gt; &quot;urn:ietf:params:oauth:grant-type:jwt-bearer&quot;, &quot;assertion&quot; -&gt; jhead &lt;&gt; &quot;.&quot; &lt;&gt; jreq &lt;&gt; &quot;.&quot; &lt;&gt; encrypted}|&gt;, VerifySecurityCertificates -&gt; True];

(* Step 6: Execute the POST Request. *)
res = URLExecute[url];

(* Handle JWT Errors. *)
If[KeyExistsQ[res, &quot;error&quot;], Return[Message[JWTError::InvalidJWT, res[[2, 2]]]]];

(* Step 7: Return as an Association. *)
&lt;|&quot;Token&quot; -&gt; Iconize[res[[1, 2]], &quot;Secret Token&quot;], &quot;Expires&quot; -&gt; Quantity[res[[2, 2]], &quot;Seconds&quot;], &quot;Type&quot; -&gt; res[[3, 2]]|&gt;

];

To get the BigQuery token, just do:

GetBigQueryToken["path_to_key.json"]
Cabral
  • 138
  • 2
  • 8