simplegoogleidtoken is a lightweight Java library for effortlessly exchanging Google Cloud Service Account credentials for Google ID tokens
This library is intended to simplify the process of exchanging Google Cloud Service Account credentials for Google ID tokens. It is configurable so when used in GCP the service account assigned to the infrastructure can be used to generate the Google ID token. When used in other envirioment the service account credentials JSON file can be provided and used to request the Google ID token.
The tokens are generated by calling the Google https://oauth2.googleapis.com/token
endpoint with the urn:ietf:params:oauth:grant-type:jwt-bearer
grant type specifying a target audience that is included in the ID token.
The issuer of these tokens will be https://accounts.google.com
which has a JWKS endpoint available at https://www.googleapis.com/oauth2/v3/certs
.
The reasoning behind this library is not for calling Google APIs but for calling other APIs that utilize Google ID tokens for authentication. By targeting a light weight implementation for use cases outside of GCP the library is able to provide a simple and easy to obtain Google ID tokens.
This library requires Java 17 and is available in the Maven Central Repository:
<dependency>
<groupId>com.unitvectory</groupId>
<artifactId>simplegoogleidtoken</artifactId>
<version>0.0.3</version>
</dependency>
When utilizing this library and running on GCP the google-auth-library-oauth2-http
library is required. This library is available on Maven Central and must be included in addition to simplegoogleidtoken
. This optional dependency is not needed if the service account credentials JSON file is provided directly. This is intentional to reduce the number of required dependencies which is limited to only GSON as the mandatory dependency.
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.23.0</version>
</dependency>
This library provides SimpleGoogleIdToken
which uses SimpleRequest
to specify the target audience and SimpleResponse
to return the ID token. In the case of an error the SimpleSignException
or SimpleExchangeException` will be throw.
When running on GCP this library can utilize the metadata service to obtain the ID tokens without the need to have the service account credentials JSON file. The default behavior for SimpleGoogleIdToken
is to use the metadata service to obtain the ID token using the ServiceAccountDefaultGoogleCredentialsConfig
configuration object which does not need to explicitly be provided.
package example;
import com.unitvectory.simplegoogleidtoken.SimpleGoogleIdToken;
import com.unitvectory.simplegoogleidtoken.SimpleRequest;
public class GCPExample {
public String getIdToken() {
String audience = "https://example.com";
SimpleGoogleIdToken simpleGoogleIdToken = SimpleGoogleIdToken.builder().build();
String idToken = simpleGoogleIdToken
.getIdToken(SimpleRequest.builder().withTargetAudience(audience).build()).getIdToken();
return idToken;
}
}
When running outside of GCP the service account credentials JSON file can be provided to the library. The ServiceAccountFileConfig
configuration object can be used to provide the path to the service account credentials JSON file. Alternatively ServiceAccountJsonConfig
can be used to provide the service account credentials JSON as a string directly.
package example;
import com.unitvectory.simplegoogleidtoken.ServiceAccountFileConfig;
import com.unitvectory.simplegoogleidtoken.SimpleGoogleIdToken;
import com.unitvectory.simplegoogleidtoken.SimpleRequest;
public class LocalExample {
public String getIdToken(String serviceAccountKeyFilePath) {
String audience = "https://example.com";
SimpleGoogleIdToken simpleGoogleIdToken = SimpleGoogleIdToken.builder().withServiceAccountConfig(
ServiceAccountFileConfig.builder().withFilePath(serviceAccountKeyFilePath).build()).build();
String idToken = simpleGoogleIdToken
.getIdToken(SimpleRequest.builder().withTargetAudience(audience).build()).getIdToken();
return idToken;
}
}
How does GCP's API work for Identity tokens? This is accomplished through Google's OAuth endpoint. The following is a brief overview of how this token exchange occurs which is also a description of what this library implements, this isn't particurally complicated.
The POST payload here is a application/x-www-form-urlencoded
payload with a grant type of urn:ietf:params:oauth:grant-type:jwt-bearer
with the assertion
parameter including the JWT from the service account.
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=TOKENHERE
The assertion is a JWT with the following format...
The header Google expects for this are:
{
"alg": "HS256",
"typ": "JWT"
}
The payload is as follows with the key input being target_audience
as this will be the audience of the generated token.
{
"iss": "example-service-account@example.iam.gserviceaccount.com",
"sub": "example-service-account@example.iam.gserviceaccount.com",
"aud": "https://oauth2.googleapis.com/token",
"iat": 1723155553,
"exp": 1723159153,
"target_audience": "https://targetaudience.example.com"
}
In the case that a JSON file from a GCP service account is being used, that JSON file looks like the following. The two key attributes here are client_email
which is used in bothe the iss
and sub
of the JWT that is being sigened and the private_key
that is being used for the signing.
{
"type": "service_account",
"project_id": "example",
"private_key_id": "00000000000000000000000000000000000000000",
"private_key": "-----BEGIN PRIVATE KEY-----\nPRIVATEKEYGOESHERE\n-----END PRIVATE KEY-----\n",
"client_email": "example-service-account@example.iam.gserviceaccount.com",
"client_id": "0000000000000000000000",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/example-service-account%40example.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}