Question
Brian Shingle · Nov 18, 2020

JWT generation for Google

Greetings!

The application I work with has a need to update a user's google password using a service account and no user intervention other than clicking a link.  
I'm in the process of figuring out how to do that from an IRIS server.
I've set up an OAuth 2.0 client with one client configuration, attempting to follow the documentation in https://community.intersystems.com/post/intersystems-iris-open-authoriza... as much as possible.  
I also set up an SSL configuration to be used with Google.  
I have extremely limited confidence that any of this is set up correctly.  
I've also created a service account on google and generated the keys which I've uploaded into the "JSON Web Tokens Settings" on the OAuth 2.0 Client->Server Description page in the portal.  
My understanding is that I need to generate a valid JWT to send to Google, at which point they'll send back an access token so I can use that to call the Google API.

Can anyone point me in the right direction as far as generating the JWT to send to Google?

Thanks,
Brian

00
2 0 6 78

Replies

JWT, is mostly on the server-side in such relations. And in your case, I suppose google should send it. Could you please share the exact Google API you are going to use? It would be easier to understand what are you going to achieve and how to help. 

There is a way, on how to generate JWT in IRIS or in Caché latest versions, but I'm just not sure, that you are going the right way.

Hey Dmitriy, thanks for the reply.  Here's ultimately what I'll use https://developers.google.com/admin-sdk/directory/v1/reference/users/update which won't be a problem (I think) once I get the access token from google.  I'm attempting to use a service account, and here are the steps that need to be achieved in order to do that (according to google documentation in this link https://developers.google.com/identity/protocols/oauth2/service-account):

After you obtain the client ID and private key from the API Console, your application needs to complete the following steps:

  1. Create a JSON Web Token (JWT, pronounced, "jot") which includes a header, a claim set, and a signature.
  2. Request an access token from the Google OAuth 2.0 Authorization Server.
  3. Handle the JSON response that the Authorization Server returns.

So it is step 1 that I'm trying to accomplish.

Thanks,

Brian

Well, I have not used Admin SDK in google, yet. And it was the first time, for me. But I've managed to get JWT and AccessToken, and was able to make requests. Unfortunately, configuration on the IRIS side is very tricky.

OAuth2 Client server should be filled manually

Issuer endpoint: https://oauth2.googleapis.com/token

This issuer is important

SSL configuration: created manually, only fill the name

And two required endpoints

https://accounts.google.com/o/oauth2/v2/auth

https://oauth2.googleapis.com/token

I did not use JSON file with private key here. But I've used it for X509

I did not manage to get it worked without configured X509. 

URL from `client_x509_cert_url` field in JSON provided by Google, opened it in browser, It contains three certificates in JSON. Took the latest one. Saved in file, replaced \n with end lines.

and `private_key` from file, saved as google.key. 

When press save, it compares certificate and private key if the match, it will be saved.

Back to OAuth2, create client configurations. First of all, go to JWT settings, fill just created X509.  And Request Algorithms.

On the Client Credentials, tab fill Client ID with value of `client_email` from JSON.

Back to General, tab, fill Application name, SSL configuration. Client Type as Resource server, ( by unknown reasons will hide Request algorithms group of fields on JWT tab).

And that's it. Code to create JWT

  Set p("scope") = "https://www.googleapis.com/auth/admin.directory.user"

  Set p("exp") =  ##class(%OAuth2.Utils).TimeInSeconds($ZTimestamp, 3600)
  Set p("iat") = ##class(%OAuth2.Utils).TimeInSeconds($ZTimestamp)

  Set jwt = ##class(%SYS.OAuth2.Request).MakeRequestJWT("google", .p, .tSC)
  If $$$ISERR(tSC) {
    Do $System.OBJ.DisplayError(tSC) 
    Quit
  }
  
  Write !,"JWT:",!,jwt

It Should be quite long, and have three groups, separated by dots, if it ends with a dot, means it did not find how to sign it. Check the settings.

And request access token

  Set hs = ##class(%Net.HttpRequest).%New()
 
  Do hs.InsertFormData("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
  Do hs.InsertFormData("assertion", jwt)   

  Set hs.Https = 1
  Set hs.SSLConfiguration = "google"
 
  Set tSC = hs.Post("https://oauth2.googleapis.com/token")
  If $$$ISERR(tSC) {
    Do $System.OBJ.DisplayError(tSC)
    Quit
  }
  Set response = {}.%FromJSON(hs.HttpResponse.Data)
  Set accessToken = response."access_token"
 
  Write !!,"AccessToken:",!,accessToken

And finally you can use that access token in the header Authorization, with prefix Bearer

  Set hs = ##class(%Net.HttpRequest).%New()
  Do hs.SetHeader("Authorization", "Bearer " _ accessToken)
 
  Set hs.Https = 1
  Set hs.SSLConfiguration = "google"
 
  Set tSC = hs.Post("https://www.googleapis.com/admin/directory/v1/users")
  If $$$ISERR(tSC) {
    Do $System.OBJ.DisplayError(tSC)
    Quit
  }
  Set response = {}.%FromJSON(hs.HttpResponse.Data)

Thank you Dmitriy, I very much appreciate the detailed response!  I'll attempt to apply this in my environment and let you know how it goes.
 

Hi Dmitriy, after following what you did to generate a JWT, I was unsuccessful.  When making the call to MakeRequestJWT, the value I receive in tSC is

"0"_$lb($lb(8894,"none","",,,,,,,$lb(,"%SYS",$lb("e^zObjectToJWT+7^%OAuth2.JWT.1^1","e^zMakeRequestJWT+46^%SYS.OAuth2.Request.1^1","e^^^0"))))/* ERROR #8894: Invalid algorithm combination.  keyalg:none, encalg:. */

Seems to point to a problem with the client configuration.  I was successfully able to create the X509 credentials and there's not much to the OAuth Client 2.0 Server description, but there seems to be so many different combinations of values in the client config...I will continue to plug away to see if I can get a win here.  Thanks again for your help!

Well this is interesting.  I started digging into the %SYS.OAuth2.Request.MakeRequestJWT code and saw the following:

I would think keyalg should be set to null when keyalg="none" rather than encalg.

I'm running v2019.1, perhaps this has been fixed in a later version.