Skip to content

Instantly share code, notes, and snippets.

@wvanderdeijl
Last active June 9, 2022 09:56
Show Gist options
  • Save wvanderdeijl/3e12856a4f1ec407493a60b78fb741bc to your computer and use it in GitHub Desktop.
Save wvanderdeijl/3e12856a4f1ec407493a60b78fb741bc to your computer and use it in GitHub Desktop.
OAuth Client Authentication using Google Service Account

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.

Get Google Service account token

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`

Invoke Identity Provider with google token to get an access token

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment