- Single Sign-On covers member login with OIDC or SAML and SCIM provisioning. Workload federation is for machine identities, not for people signing in.
- Session identity tokens covers the reverse direction, where Orq.ai issues OIDC tokens that AWS, Google Cloud, Vault, and other relying parties verify.
Use cases
A workload is any process that calls Orq.ai with no person driving it, authenticating with an identity its own platform already issues. It is not an Orq.ai API key, and it is not a person signed in to the dashboard. A CI/CD job, a scheduled batch job, a backend service, a long-running application, or a deploy pipeline all qualify.The issuer’s discovery document must be reachable from the public internet, so an in-cluster Kubernetes issuer works only when it is published that way.
- Run evaluations from CI. A GitHub Actions workflow on one repository’s
mainbranch, bound torepository_idandref. - Sync Prompts from a pipeline. A GitLab CI pipeline bound to
project_idandref. - Call the AI Gateway from a service. A backend service behind Keycloak, Okta, Auth0, or Microsoft Entra ID, bound to its
azporappid. - Reach the production Deployment only from a protected environment. A pipeline bound to
repository_idandenvironment. - Export usage on a schedule. A
Read onlytrust that cannot create or change anything.
How it works
- The workload asks its identity provider for an OIDC token with a specific
aud(audience) value. - The workload sends that token to the Orq.ai token exchange endpoint.
- Orq.ai finds the trust configuration matching the token’s issuer and audience, verifies the signature against the issuer’s published keys, and checks the token’s claims against the configured rules.
- Orq.ai returns a short-lived API key limited to the permissions and project on the trust configuration.
- The workload uses the key as a normal Bearer token until it expires.
Prerequisites
- A workspace on the Enterprise plan. Configuring SSO first is not required.
- Workspace admin rights to manage trust configurations.
- An identity provider that issues OIDC JWTs and publishes its signing keys through OpenID discovery. The discovery document and signing keys must be reachable from the public internet.
- Workload federation is tested with GitHub Actions (including GitHub Enterprise Server) and Keycloak. Other providers such as GitLab CI, Okta, Auth0, and Microsoft Entra ID work when their tokens meet the requirements under Exchange a token.
Create a trust configuration
Go to Settings > Organization > Workload federation and click Add trust configuration.
An existing configuration can be disabled from its edit view to stop exchanges without deleting it.
An issuer and audience pair can belong to only one enabled trust configuration across all of Orq.ai. If a pair is already in use, the configuration is refused; keep the generated audience to avoid this.
Set up GitHub Actions step by step
This walkthrough lets themain branch of the acme/evals repository call the AI Gateway.
-
Find the repository’s numeric ID using any of these:
- Browser (public repositories): open
https://api.github.com/repos/acme/evalsand copy the top-level"id"value. - GitHub CLI (public or private):
gh api repos/acme/evals --jq .id - From a workflow run: add a step with
echo "${{ github.repository_id }}". Usegithub.repository_owner_idfor the organization ID.
812345678. Replaceacme/evalswith the target repository. - Browser (public repositories): open
-
In Orq.ai, go to Settings > Organization > Workload federation, click Add trust configuration, and fill in:
-
In the GitHub repository, go to Settings > Secrets and variables > Actions > Variables and add a repository variable
ORQ_AUDIENCEwith the copied audience. The audience is not a secret, so a variable is enough. -
Add the workflow from GitHub Actions to
.github/workflows/. -
Push to
main. The job exchanges its GitHub token for an Orq.ai API key and calls the AI Gateway. The exchange appears in Settings > Organization > Audit logs asfederation.exchange.granted, with the token subject.
invalid_target, see Troubleshooting.
Claim rules
A rule is a list of conditions. A token is accepted when every condition of any single rule matches. Rules are combined with OR, conditions within a rule with AND. Each condition names a claim and lists its allowed values:- A value without
*must match the claim exactly. - A value containing
*is a glob anchored at both ends.*matches any characters except:, sorepo:acme/*:ref:refs/heads/maincannot be widened by a token whosesubcontains extra:segments. - A missing claim, or a claim that is not a string, fails the condition.
Which claims to use
Every OIDC provider puts different claims in its tokens. The ones that identify a workload or a person:
To see the exact claims and values a provider sends, decode one of its tokens before writing rules:
A live subject token is the credential itself, so decode it locally. An already-expired token is safe to paste into an online decoder such as jwt.io, and nothing needs decoding on the Orq.ai side: the exchange endpoint verifies the signature itself.
Common rules
Conditions in the same rule are ANDed, so each row above accepts only tokens that satisfy every condition in it.
- To allow alternatives, add a rule per alternative. To accept two repositories, create two rules, each binding its own
repository_id; a token from either repository matches one of them and is accepted. - To allow several values in one condition, list them.
refwithrefs/heads/mainandrefs/heads/releaseaccepts a token from either branch.
GitHub Actions rules
GitHub Actions tokens have two additional requirements. Bind a numeric ID. Every rule must bindrepository_id or repository_owner_id to a value without *. Repository and organization names can be renamed or transferred; the numeric IDs cannot. To find them:
- Open
https://api.github.com/repos/<owner>/<repo>for a public repository, or rungh api repos/<owner>/<repo> --jq .id. The organization ID is.owner.idin the same response. - Inside a workflow,
${{ github.repository_id }}and${{ github.repository_owner_id }}print the exact values the token carries.
push,workflow_dispatch,schedule,release,create,deployment,deployment_status.
pull_request from a fork or a merge queue, is rejected unless every rule has an event_name condition with exact values. A value containing * does not count.
To accept pull request workflows on purpose, add an
event_name condition to each rule and list every accepted event, for example push and pull_request. A rule with only event_name = pull_request rejects tokens from pushes.Exchange a token
The exchange endpoint implements OAuth 2.0 Token Exchange (RFC 8693).
No Orq.ai credential is sent. The subject token is the credential.
A successful response returns the key:
expires_in is the lifetime configured on the trust configuration, independent of the subject token’s own expiry.
The subject token must:
- Be signed by the issuer’s current keys, with
issequal to the trust configuration’s issuer URL. - Contain the trust configuration’s audience in
aud. - Have been issued (
iat) within the last 10 minutes. - Carry a
jticlaim. Each token can be exchanged once.
Errors
Use the key
The minted key is a standard Orq.ai API key.- Send it as
Authorization: Bearer <key>to the platform API, the AI Gateway, and an MCP Gateway. - Scope: the granted permissions and the pinned project only.
- Lifetime: it stops working when it expires.
- Audit: each grant is recorded as
federation.exchange.granted, with the trust configuration, the token subject, the key ID, and its expiry.
Examples
GitHub Actions
ORQ_API_KEY, so every later step uses it exactly as it would a stored API key.
- The CLI reads
ORQ_API_KEYdirectly.ORQ_NO_INPUT=1makes it fail instead of prompting, so a misconfigured job errors out rather than hanging. - The SDKs read the same variable. The step can just as well be a script using the Node SDK (
@orq-ai/node) or the Python SDK (orq-ai-sdk). id-token: writeis required. Without it, GitHub does not issue an OIDC token to the job.
ORQ_AUDIENCE is the repository variable from Set up GitHub Actions step by step.
The trust configuration for this workflow uses issuer
https://token.actions.githubusercontent.com, one rule with repository_id set to the repository’s numeric ID and ref set to refs/heads/main, and grants the Chat completions permission.Keycloak
Orq.ai reads the audience from the ID token, not the access token.-
In Keycloak, open the client the workload uses, then make the ID token carry the audience:
- Simplest: create the trust configuration with the client ID as its audience, because Keycloak already puts the client ID in the ID token’s
aud. - Explicit: add an Audience mapper to the client with Included Custom Audience set to the trust configuration’s audience and Add to ID token turned on.
- Simplest: create the trust configuration with the client ID as its audience, because Keycloak already puts the client ID in the ID token’s
-
Create a trust configuration with issuer
https://<keycloak-host>/realms/<realm>and a rule that limits who may exchange, for exampleazp=<client-id>for one application oremail=jane@example.comfor one user. -
Request tokens with
scope=openidso Keycloak returns an ID token, then exchange it:
Other OIDC providers
Request an ID token from the provider with the trust configuration’s audience inaud, then send it to the exchange endpoint as shown above. Add a rule on a claim such as preferred_username, email, or sub to limit which principals may exchange tokens.
Troubleshooting
Every token rejection returns the sameinvalid_target error. Open Settings > Organization > Audit logs and look for federation.exchange.denied on the trust configuration. The reason names what to fix:
If no denied entry appears, Orq.ai could not link the token to a trust configuration, could not verify it, or the per-trust denial-audit budget was exhausted. Check that:
- The token’s
issexactly matches the Issuer URL, including the scheme and without a trailing slash. - The token’s
audcontains the trust configuration’s audience, and the same audience is sent in theaudienceparameter. - The issuer’s discovery document and signing keys are reachable from the public internet, and the token is signed with one of those keys.
- The trust configuration is enabled.
- The workspace is on the Enterprise plan.
Security
- Token rejections return the same generic error, so a caller cannot discover which issuers or audiences are configured.
- Each subject token can be exchanged once. Replays are rejected.
- Subject tokens older than 10 minutes are rejected regardless of their own expiry.
- Exchanges are limited to 60 per minute per trust configuration.
- Granted exchanges, and denials of correctly signed tokens meant for a trust configuration, are recorded in the workspace audit log. Denials are capped at 20 per minute per trust configuration.
- Keys minted from a configuration created in the dashboard are pinned to its project, and no minted key can hold workspace administration permissions.
- Issuer discovery and key fetches refuse redirects.
Limitations
- A workspace holds up to 100 trust configurations.
- Trust configurations are managed by workspace admins from the dashboard. They cannot be created or edited with an API key.
- The trust configuration’s audience must appear in the token’s
aud. If the identity provider cannot add a custom value, use a value it already sends, such as the client ID, as long as no other trust configuration uses the same issuer and audience. - Identity providers on a private network are not supported. Orq.ai must be able to fetch the issuer’s discovery document and signing keys over the public internet.