Skip to main content
Workload identity federation lets a workload that already holds a JWT from your identity provider call OpenRouter without an OpenRouter API key in its environment. The workload exchanges its JWT for a short-lived OpenRouter access token (RFC 8693 token exchange) and sends that token as the bearer on inference requests, or on organization management requests such as the Terraform provider’s.
Workload identity federation is available on Business and Enterprise plans. Organizations on those plans find it under Settings → Workload identity. Organization admins can upgrade to the Business plan under Account Type in Settings → Preferences. For Enterprise, contact our enterprise team.

How it works

  1. Your identity provider signs a JWT for the workload (a service account, a CI job, a Kubernetes pod).
  2. The workload posts that JWT to POST https://openrouter.ai/api/v1/oauth/token.
  3. OpenRouter verifies the signature against your issuer’s published keys, finds the federation policy that names the token’s sub and aud, and mints an OpenRouter access token that acts as the API key the policy targets.
  4. The workload calls https://openrouter.ai/api/v1/... with Authorization: Bearer <access_token> until the token expires, then exchanges again.
Access tokens live for 15 minutes at most, and never longer than the JWT that was exchanged for them. Usage is attributed to the target API key exactly as if that key had been used directly.

Set up trust

Everything is configured by an organization admin under Settings → Workload identity.

1. Add an issuer

An issuer is an identity provider your organization trusts.

2. Add a policy

A policy says which tokens from an issuer may exchange, and which API key they act as. A policy must set at least one of Subject or Condition. Each policy has an id shown under its name. Your workload sends that id as federation_policy_id with every exchange, which binds the exchange to your organization even if another organization trusts the same issuer, subject, and audience. Policies can be paused with the Enabled switch. Under Token must match, choose Add claim check to add either of these optional conditions: All added checks must pass, in addition to issuer, subject, audience, signature, and expiry validation. Matching is case-sensitive; missing or incorrectly typed claims fail the exchange. Each check can be added once and removed independently. Policies without additional checks keep their existing behavior. These conditions validate the incoming identity token. They do not change the scope or Bearer token type of the issued OpenRouter access token, and sending scope in the exchange request does not satisfy a subject-token check.

Conditions

When an exact subject is too narrow, write a Condition in CEL. It is evaluated after signature, expiry, exact subject and audience, and claim checks pass, and it sees only these variables from the verified token: Read the sub claim from a real token before you write a condition. Issuers differ in the form they use, and a condition written against the wrong form never matches, which then surfaces only as the generic invalid_grant described under Errors. GitHub Actions emits two formats. Repositories created, renamed, or transferred after July 15, 2026 use an immutable subject that carries the permanent owner and repository IDs. Existing repositories can also opt in at the organization or repository level through the OIDC settings UI or REST API. Those IDs stay in place even when the subject claim is customized with include_claim_keys. A condition written for the older name-only form cannot match such a token. See GitHub’s OpenID Connect reference for the transition rules, and check the actual token rather than relying on the repository’s creation date. GitHub Enterprise Server always uses the name-only form.
Example conditions
The expression is parsed and type-checked when the policy is saved: it must be at most 2,000 characters, use only the variables above, and evaluate to a boolean. matches() (regular expressions) is not available. At exchange time, a condition that evaluates to false, errors, or receives a token whose scopes or token_type claim has the wrong type rejects the exchange with invalid_grant. Subject tokens whose sub or any aud value exceeds 512 characters, or whose scopes claim has more than 16 entries or an entry longer than 512 characters, are rejected before any rule is evaluated. Comprehension macros (all, exists, filter, map, and similar) cannot be nested inside one another.

Exchange a token

Token exchange
Response
Then call the API with the access token as the bearer:
Inference with an access token
The request body is application/x-www-form-urlencoded and must stay under 32 KB; subject_token itself is capped at 16 KB. federation_policy_id is required and names the policy to evaluate. requested_token_type (must be urn:ietf:params:oauth:token-type:access_token) and scope are accepted and optional. When sent, scope must be the scope the policy grants (inference for a workspace key, management for a management key); when omitted, the token gets the policy’s scope; audience and resource are accepted and ignored.

Manage your organization with an access token

A policy that acts as a management key issues tokens with "scope": "management". Send that token as the bearer to the management API exactly as you would send the management key itself. It has the same access level and permissions as the key, so a read-only management key yields a read-only token. A management token is refused on inference endpoints, and an inference token is refused on management endpoints.
A management key can create and delete API keys, change guardrails, and manage workspaces for the whole organization. Pin management-key policies to the narrowest subject you can, for example a protected CI branch, and add claim checks or a condition for anything else your identity provider asserts.
List workspaces with a management-scoped access token

Use an access token with the Terraform provider

The OpenRouter Terraform provider performs the exchange itself, so no API key is stored in the configuration or the environment. Point it at the policy and at the file holding the workload’s JWT:
Both values can also come from the environment, as OPENROUTER_FEDERATION_POLICY_ID and OPENROUTER_OIDC_TOKEN_FILE. The provider requests the management scope, so its policy must act as a management key; a policy acting as a workspace key is refused. Setting api_key or OPENROUTER_MANAGEMENT_KEY together with federation_policy_id is a configuration error, so a plan cannot fall back to a stored key. The token file is re-read on every exchange, so a rotated token is picked up without a restart.

Requirements on the subject token

  • Signed with ES256 or RS256 by a key published at the issuer’s JWKS.
  • Carries iss, sub, aud, and exp, and is not expired.
  • iss equals the issuer URL of the named policy. One aud value equals the policy’s audience. If the policy sets a subject, sub equals it.
  • Satisfies every additional claim check and the condition configured on the policy.

Errors

Errors follow RFC 6749 §5.2:

Verifying OpenRouter access tokens

Access tokens are JWTs (typ: at+jwt) signed by OpenRouter with ES256. The public keys are published at https://openrouter.ai/api/v1/oauth/jwks. The sub of an access token is the sub of the exchanged JWT, and federation_policy_id and federation_issuer_id name the policy and issuer that authorized it, for auditing on your side. OpenRouter does not read them when authorizing a request.

Revocation

Deleting or pausing a policy, deleting an issuer, or losing the workload identity entitlement stops new exchanges immediately. Access tokens already issued remain valid until they expire, which is at most 15 minutes — none of those changes revokes an outstanding token. To cut off access within that window, disable or delete the API key the policy targets: key state is checked on every request.