In previous post, we saw how to authenticate and retrieve files from google drive using OAuth2. During the OAuth2 dance, user needs to manually enter the credentials to be successfully authenticated. What if the account you are using to authenticate is a system account or if you dont want to show the OAuth2 dance workflow and still need to retrieve the files from google drive?
Alternatively to OAuth2 dance, one can use a JSON Web Token(JWT pronounced as “jot”) is a URL safe means of representing claims to be transferred between two parties. Inorder to use JWT authentication with google drive, below are high level steps:
- Create a service account key on google cloud
- Create a Mule application which will have following workflow:
- Java component to
- use google credential library and read the service account key file (optional as you can just open the key file which is in json format and copy the key values)
- use JWT library to created the signed JWT
- HTTP Request connector to call google drive token api with the signed JWT to get the token
- HTTP Request connector to call google drive file api with the token to retrieve files from google drive
- Java component to
Step 1: Create service account key on google cloud
Logon to https://console.developers.google.com/ , click on Credentials tab on the left and click Create credentials drop down button
Select drop down New service account and enter the details as below:
Once you hit create button, service account key file is downloaded to your computer. We will need details from this file to generate the JWT token. If you loose this file, you will have to perform above steps again and generate a new file. The service account keys json file should look something like below:
Step 2: Create mule application
Create a new mule application where we will write logic to use service account keys and generate signed JWT. JWT will further be used to create a token which is required to call the google drive file api.
Below is how the completed mule application flow will look:
In subflow, we are generating a JWT, setthing the payload with JWT to call token service and use the token generated to call /files api on google drive.
Below is the code snippet for generating JWT.
[code] Algorithm algorithm = Algorithm.RSA256(null, (RSAPrivateKey) privateKey); String signedJwt = JWT.create() .withIssuer(accountId) .withAudience(audience) .withIssuedAt(new Date(now)) .withClaim("scope", "https://www.googleapis.com/auth/drive") .withExpiresAt(new Date(now + 3600 * 1000L)).sign(algorithm); [/code]
From the code above, privateKey, accountId are retrieved from service account keys file which we generated as part of Step 1. You can choose to either directly copy it or use Google credential library to read the contents of the file and populate it. Below code snippet shows the later option:
[code] GoogleCredential credential = GoogleCredential.fromStream(CreateDriveJWT.class.getResourceAsStream("/mule-googledrive-serviceacct.json")); PrivateKey privateKey = credential.getServiceAccountPrivateKey(); String accountId = credential.getServiceAccountId(); String audience = "https://accounts.google.com/o/oauth2/token"; [/code]
Dependencies: Inorder to use the above snippets, make sure you add below dependencies and import the libraries:
<!-- JWT and google client dependency --> <dependency> <groupId>com.google.api-client</groupId> <artifactId>google-api-client</artifactId> <version>1.20.0</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>com.google.apis</groupId> <artifactId>google-api-services-drive</artifactId> <version>v3-rev86-1.23.0</version> </dependency>
[code] import java.security.PrivateKey; import java.security.interfaces.RSAPrivateKey; import java.util.Date; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.auth.oauth2.*; import com.google.api.client.json.jackson2.JacksonFactory; [/code]
Once you have generated the JWT, the next step is to call the token service with below payload where flowVars.googledriveJWT is holding the JWT value generated in above step:
[code] grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=#[flowVars.googledriveJWT] [/code]
The response from token service api should like:
{
“access_token”: “ya29.c.Ell0BuB3PmuW3f8f_CK3AOWGAvsvYimHDHjn5Z0EAHJER1qfRvNq1EONiX8TONsZDqO_Tno-Gq3Ja57RW-d7kNOgvkB0quFjmhlOhksQ8Vh1FFDh174-2tX7og”,
“expires_in”: 3600,
“token_type”: “Bearer”
}
After the drive token is successfully retrieved, you will need the access_token value from above response to call google drive /files resource. “access_token” value is passed as Authorization header in the api configuration. Below is the configuration for calling /files api
Once all of these steps are performed, calling the mule service will return you the files from google drive. API response should look like below
NOTE: Since you are using the service account, only the files created by the service account will be retrieved and any files created by other user will not be retrieved. To test this out, make sure you upload a file using the service account. You can do this by using access token and calling below service to upload a file:
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=media
with body as binary content
If you need to see detailed version about the file or permissions you can change the api version to /v2 during the GET /files call. v2 will give you more details than what is shown on v3 version of api
Mule application for this blog can be found at GITHUB
References:
JWT: https://jwt.io
Using JWTs with google cloud: https://cloud.google.com/iot/docs/how-tos/credentials/jwts
Uploading file to drive: https://developers.google.com/drive/api/v3/manage-uploads