Google Workspace
Wiring Google Identity (Workspace) as Flux's OIDC identity provider — OAuth client setup, the hd claim, and domain restriction.
Google Workspace is the organizational layer; the OIDC surface that issues tokens is Google Identity Platform, configured through Google Cloud Console. Flux validates Google-issued ID tokens against Google’s well-known discovery document the same way it validates tokens from any OIDC IdP. The Flux-side contract is in Configuring OIDC; this page covers what to set up in Google Cloud and the one Workspace-specific gotcha (the hd claim).
What to register at Google Cloud
Two pieces, in your Google Cloud project tied to your Workspace org:
- OAuth consent screen. Set User Type to “Internal” if you want only your Workspace domain to be able to sign in (this is the canonical Workspace restriction). External + a Workspace-domain restriction at the IdP level is the other option.
- OAuth 2.0 Client ID. Application type depends on the caller:
- Web application for browser flows. Add your frontend’s redirect URI (Flux itself does not host one).
- Desktop / Service account for non-interactive flows. For server-to-server, use a service account with a JSON key and the standard OAuth 2.0 service-account JWT flow to obtain an ID token.
The client ID is what Google puts into the aud claim of ID tokens. You will use this client ID as Flux’s audience setting.
Issuer URL is https://accounts.google.com — no trailing slash, no path. Discovery lives at https://accounts.google.com/.well-known/openid-configuration (Google also advertises https://www.googleapis.com/oauth2/v3/certs as the JWKS URI inside that doc).
Signing algorithm is RS256.
Vendor-specific gotchas
- Google uses ID tokens, not access tokens, for OIDC validation. Google’s OAuth access tokens are opaque (a long random string), not JWTs. Flux validates JWTs, so callers must send the ID token, not the access token. The ID token is in the
id_tokenfield of the OAuth response; the access token is inaccess_tokenand is irrelevant to Flux’s authentication path. hd(hosted domain) claim. For users in a Workspace org, Google adds anhdclaim containing the Workspace domain (e.g.,example.com). Flux does not readhd— there is no Flux config field that restricts by domain. Restrict via the Workspace org itself (Internal OAuth consent screen) or via a Workspace-side admin policy. If you have an external OAuth consent screen and want only your domain through Flux, you need to layer that check somewhere in front of Flux (a reverse proxy or an admission webhook); the Flux OIDC provider will issue identities for any Google account whose token validates.subis the user’s Google account ID. It is stable per user per OAuth client. Across OAuth clients, the same user has differentsubvalues — so if you migrate clients, your principals registry loses its lookup keys.- Service accounts as Flux principals. A Workspace service account that signs its own JWT and exchanges it for an ID token will appear in Flux with
subset to the service account’s numeric ID. This is fine for non-interactive workflows; treat it like an API key bound to a Google identity. - Domain-wide delegation. Workspace admins can grant a service account permission to impersonate users. The resulting ID token’s
subis the impersonated user, not the service account, so the principal Flux sees is the user. Use this deliberately; Flux has no signal that the call was impersonated. - Issuer flavor. Google sometimes advertises
https://accounts.google.comand sometimesaccounts.google.com(no scheme) iniss. Flux compares exact-match. The discovery document settles which one applies — use whatever theissuerfield inhttps://accounts.google.com/.well-known/openid-configurationsays.
The minimal Flux config
[flux.security.auth.oidc]
enabled = true
issuer = "https://accounts.google.com"
audience = "1234567890-abcdefghij.apps.googleusercontent.com"
default_user_roles = ["viewer"]
The audience is the OAuth 2.0 client ID from Google Cloud Console; the trailing .apps.googleusercontent.com is part of the value. default_user_roles opts into auto-provisioning; omit it to require explicit flux principals create for every user.
Defaults for jwks_cache_ttl (3600s) and clock_skew (30s) are fine.
Verification
curl -s https://accounts.google.com/.well-known/openid-configuration | jq .
Confirm issuer matches your Flux config exactly (Google’s canonical value is https://accounts.google.com). Confirm id_token_signing_alg_values_supported contains RS256.
Obtain an ID token. The simplest path for testing is a service account with a JSON key:
gcloud auth print-identity-token --audiences=<your-client-id>.apps.googleusercontent.com
(Run as the service account; needs gcloud auth activate-service-account first.) Decode the payload and verify iss, aud, exp, sub are all present, and that aud is exactly your configured client ID.
Hit a Flux endpoint:
curl -H "Authorization: Bearer $ID_TOKEN" https://flux.example.com/workflows
Flux logs Auto-provisioned principal <sub> on first sign-in (when default_user_roles is set) or OIDC token validation failed: Invalid audience if the token came from a different OAuth client.
See Configuring OIDC for the four required claims, the deprecation of roles_claim, and how Flux resolves principals from (sub, iss).
Derived against Google Identity docs 2026-05.