Some identity providers support OAuth client authentication using the private_key_jwt
authentication method. This means you invoke the oauth token endpoint with a JWT that is signed using a private key and a client_assertion_type
set to urn:ietf:params:oauth:client-assertion-type:jwt-bearer
. They identity provider than validates the token using the public key and issues an access token.
In the setup at the identity provider you have to create an OAuth client, set it up to use private_key_jwt
as the authentication method and supply a URL to the JWKS (JSON Web Key Set) that contain the public key(s). This makes this flow very easy to implement with a Google service account since Google publicly hosts the JWKS for each service account at https://www.googleapis.com/service_accounts/v1/jwk/SERVICE_ACCOUNT_EMAIL
. Having the identity provider fetch the JWKS from a public endpoint adds security as it allows for frequent service account key rotation at the side of Google without the need to reconfiger the identity provider to accept new public keys.
See the private_key_jwt
section of the Client Authentication section in the openid specification for the requirements for the claims in the initial JWT. Also check the documentation of your identity provider as some have slightly different requirements to the claims in the tokens (talking about you Microsoft Azure)
These examples assume you are requesting a token for an OAuth client acting on behalf of itself. A similar flow exists when the client is acting on behalf of a user where the grant_type
in the request should be urn:ietf:params:oauth:grant-type:jwt-bearer
.
SERVICE_ACCOUNT=my-service-account@my-project.iam.gserviceaccount.com
CLIENT_ID=identity-provider-oauth-clientid
AUD=https://my-identity-provider.example/token.oauth2
TOKEN=`jq -n \
--arg aud $AUD \
--arg iss $CLIENT_ID \
--arg time_str "$(date +%s)" \
'{aud: $aud, iss: $iss, sub: $iss, iat: ($time_str | tonumber), exp: ($time_str | tonumber + 300)}' \
| gcloud beta iam service-accounts sign-jwt /dev/stdin /dev/stdout --iam-account=$SERVICE_ACCOUNT`
curl -i -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=$CLIENT_ID&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=$TOKEN" \
$AUD