8
$\begingroup$

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:

$\endgroup$
5
$\begingroup$

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["Retrieving Token ", ProgressIndicator[Appearance -> "Percolate"]];

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

    (* Step 2: Build "Header" JSON. *)
    jhead = EncodeBase64[ExportString[<|"alg" -> "RS256", "typ" -> "JWT"|>, "JSON", "Compact" -> True]];

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

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

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

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

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

    (* Step 7: Return as an Association. *)
    <|"Token" -> Iconize[res[[1, 2]], "Secret Token"], "Expires" -> Quantity[res[[2, 2]], "Seconds"], "Type" -> res[[3, 2]]|>

];

To get the BigQuery token, just do:

GetBigQueryToken["path_to_key.json"]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.