Workload identity federation

One /v1 endpoint for every provider. Point your OpenAI client at a new base URL and key, bring your own provider keys, and pay 0% markup on tokens.

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.

Federation is available on every plan and is set up by an Owner or an Admin. The token acts as the key you choose, so that key’s spending limit, workspace, IP allowlist and pause all apply. Revoking or pausing the key stops every token issued for it.

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 https URL that publishes /.well-known/openid-configuration.
  • Subject (sub): the exact sub claim 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=value per 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/BRANCH for a branch, or repo:OWNER/REPO:environment:NAME for 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:
curl
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:
curl
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
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
json
{
  "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, sub or aud: 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.
  • 503 temporarily_unavailable: token exchange is not switched on for this deployment yet.