Workload identity federation lets an automated job call the API without storing an API key. The job already has an identity token from its platform, such as a GitHub Actions run, a Google Cloud service account or a Kubernetes service account. It sends that token to us and gets back a token that lasts at most 15 minutes and works like one of your inference keys.
Step 1: Choose the key it acts as
Create an inference key for this workload under Keys, with a spending limit that suits it. A key of its own makes its spending easy to see and to stop. You never copy this key anywhere: the policy only points at it.
Step 2: Add a policy
In Settings → Workload identity federation, select Add policy and fill in:
- Issuer URL: who signs the workload’s tokens. It must be a public
httpsURL that publishes/.well-known/openid-configuration. - Subject (sub): the exact
subclaim the token must carry. This is what pins the policy to one repository, branch or service account. - Audience (aud): the exact audience the workload requests its token for. Pick a value only you use, such as
autonomousrelay. - API key it acts as: the key from step 1.
- Extra claim checks (optional): one
claim=valueper line. Each must match the token; for a list claim, the list must contain the value.
Save it and copy its Policy ID; the workload sends it with every exchange.
Step 3: Get a token from your platform
GitHub Actions
- Issuer URL:
https://token.actions.githubusercontent.com - Subject:
repo:OWNER/REPO:ref:refs/heads/BRANCHfor a branch, orrepo:OWNER/REPO:environment:NAMEfor a deployment environment. - Extra claim check (recommended):
repository_owner=OWNER. - The workflow needs
permissions: id-token: write. It requests its token with the audience you chose:
SUBJECT_TOKEN=$(curl -sS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=autonomousrelay" | jq -r .value)
Google Cloud
- Issuer URL:
https://accounts.google.com - Subject: the service account’s unique ID (the long number on its details page), not its email.
- On Compute Engine, Cloud Run or GKE, read the token from the metadata server:
SUBJECT_TOKEN=$(curl -sS -H "Metadata-Flavor: Google" \ "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=autonomousrelay")
Kubernetes
- Issuer URL: your cluster’s service-account issuer. It must be publicly reachable over
https, as it is on EKS and GKE. - Subject:
system:serviceaccount:NAMESPACE:NAME. - Mount a projected service-account token with your audience (
serviceAccountToken.audience: autonomousrelay) and read it from the file.
Other platforms
Any issuer works if its tokens are JWTs signed with RS256 (RSA keys of 2048 bits or more) orES256, and it publishes its keys through OpenID Connect discovery.
Step 4: Exchange it
Send the platform’s token and your policy ID to the token exchange URL:
curl -sS -X POST https://autonomousrelay.com/v1/oauth/token \ -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \ -d subject_token_type=urn:ietf:params:oauth:token-type:jwt \ -d subject_token="$SUBJECT_TOKEN" \ -d federation_policy_id=YOUR_POLICY_ID
{
"access_token": "eyJ...",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
"token_type": "Bearer",
"expires_in": 900,
"scope": "inference"
}Use access_token exactly as you would an API key, as Authorization: Bearer on any inference call. It never outlives the platform’s own token. Exchange again when it expires; there is no refresh token. Our public signing keys are at https://autonomousrelay.com/v1/oauth/jwks.
Pausing and deleting
Pause or Delete policy stops new exchanges at once. Tokens already issued keep working until they expire, at most 15 minutes. To stop those too, pause or revoke the key the policy acts as.
Troubleshooting
A refused exchange answers 400 with invalid_grant and a description:
- “No active federation policy has that id”: the policy ID is wrong, or the policy is paused or deleted.
- “The key this policy acts as is no longer active”: the key was revoked or has expired. Point the policy at another key.
- A message about
iss,suboraud: the token’s claim does not match the policy exactly. Decode the token (its middle part is base64 JSON) and compare. - A message about the signature: the token was not signed by one of the issuer’s published keys, or uses a key type we do not accept.
- “Could not read the issuer’s …”: we could not reach the issuer’s discovery document or keys. Check the issuer URL.
503temporarily_unavailable: token exchange is not switched on for this deployment yet.