Workload identity: Google Cloud
Workloads on Google Cloud (Cloud Run, Cloud Functions, GKE with Workload Identity, Compute Engine) run as a Google service account and can fetch a signed identity token for any audience from the metadata server. Exchange that token for a Syntic access token and no Syntic secret needs to live in Secret Manager or environment variables.
Claims you can match on
| Claim | Example | Use it to |
|---|---|---|
email | summariser@acme-prod.iam.gserviceaccount.com | Trust one Google service account. |
sub | 112233445566778899000 | The service account’s unique numeric id; does not change if the account is renamed. |
email_verified | true | Required to be true for email to be meaningful. |
Matching on sub is the most robust choice; email is easier to read. Using both is fine.
Set it up
Note the Google service account
Find the service account your workload runs as, and its unique id:
gcloud iam service-accounts describe summariser@acme-prod.iam.gserviceaccount.com --format='value(uniqueId)'Create the Syntic service account and trust rule
{
"issuer": "https://accounts.google.com",
"audience": "https://app.syntic.ai",
"conditions": {
"sub": "112233445566778899000",
"email": "summariser@acme-prod.iam.gserviceaccount.com",
"email_verified": "true"
},
"max_token_lifetime_seconds": 1800
}Fetch and exchange the token in your code
# pip install google-auth requests
import requests
import google.auth.transport.requests
from google.oauth2 import id_token
jwt = id_token.fetch_id_token(google.auth.transport.requests.Request(), "https://app.syntic.ai")
tok = requests.post(
"https://app.syntic.ai/v1/oauth/token",
headers={"syntic-beta": "token-exchange-2026-11-01"},
json={
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token": jwt,
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
"service_account": "svcacct_01JCB3D5F7H9K1M3P5R7",
},
timeout=30,
).json()
syntic_token = tok["access_token"] # valid for tok["expires_in"] secondsRefresh before expiry
Cache the Syntic token and exchange a new Google token a minute or two before expires_in runs out. Google identity tokens themselves last about an hour, and the libraries above refresh them for you.
Each Google service account should map to its own Syntic service account. Sharing one Syntic service account between several Google identities makes the audit log less useful.
Related
- Workload identity
- Kubernetes: for GKE workloads using projected Kubernetes tokens instead.
- Exchange a workload token