Repository Public
1# Workload identity federation23> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.45Workload identity federation lets a trusted workload use an identity it already6has instead of storing an OpenAI API key or ChatGPT credential. The workload7presents a short-lived token from your identity provider, and OpenAI exchanges8it for a short-lived OpenAI access token.910OpenAI API workloads can also exchange a verified certificate identity through11X.509 workload identity federation.1213You can use workload identity federation with the OpenAI API or Codex:1415| | OpenAI API | Codex |16| ---------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------ |17| **OpenAI identity** | A service account in an API Platform project | A user or service account in a managed ChatGPT workspace |18| **Where administrators set it up** | OpenAI Platform | OpenAI Admin Portal |19| **How the workload connects** | An OpenAI SDK or the token exchange endpoint | Codex environment variables and an identity-token file |20| **What the access token can use** | The APIs and permissions available to the mapped service account | The Codex access available to the mapped workspace principal |2122Both paths use the same trust model, but their administration and runtime23configuration differ. Start with the shared concepts and identity-provider24guidance below, then follow the section for the product your workload uses.2526- **OpenAI API:** Continue to [Use workload identity with the OpenAI27 API](#use-workload-identity-with-the-openai-api).28- **Codex:** See [Use workload identity with Codex](#use-workload-identity-with-codex).2930See the [Codex31federation rule32reference](https://developers.openai.com/api/docs/guides/workload-identity-federation/federation-rules) for33rule and lifecycle behavior.3435## How it works3637An administrator configures three things before the workload connects:38391. An **identity provider** tells OpenAI which external issuer to trust and how40 to verify its signed tokens or certificate identities.412. An **access rule** describes which token attributes OpenAI accepts and which42 OpenAI identity the workload may act as. OpenAI API configuration calls this43 a service account mapping. Codex configuration calls it a federation rule.443. An **OpenAI principal** receives the resulting access. For the OpenAI API,45 the principal is a Platform service account. For Codex, the principal is a46 ChatGPT user or service account in a managed workspace.4748At runtime:49501. The workload receives a short-lived OIDC JWT or SPIFFE JWT-SVID, or an OpenAI51 API workload presents an X.509 certificate.522. The workload presents its external identity with the IDs required by its53 product.543. OpenAI verifies the token or certificate, then evaluates the configured55 mapping or rule.564. OpenAI returns a short-lived access token for the mapped principal.5758Token exchange never creates a principal, project, or workspace membership.59Administrators create or select those resources during setup.6061<a id="choose-a-setup-guide"></a>6263## Get an identity token6465Choose the guide for the environment where your workload runs:66676869 - **[X.509 certificates](https://developers.openai.com/api/docs/guides/workload-identity-federation/x509)**: Configure certificate-backed exchange for OpenAI API workloads.70- **[Kubernetes](https://developers.openai.com/api/docs/guides/workload-identity-federation/kubernetes)**: Use projected service account tokens in self-managed clusters.71- **[AWS](https://developers.openai.com/api/docs/guides/workload-identity-federation/aws)**: Use outbound identity federation or Amazon EKS projected tokens.72- **[Microsoft Azure](https://developers.openai.com/api/docs/guides/workload-identity-federation/microsoft-azure)**: Use managed identity tokens or AKS projected service account tokens.73- **[Google Cloud](https://developers.openai.com/api/docs/guides/workload-identity-federation/google-cloud)**: Use metadata server identity tokens or GKE projected service account tokens.74- **[Oracle Cloud Infrastructure](https://developers.openai.com/api/docs/guides/workload-identity-federation/oracle-cloud)**: Use instance principal tokens from an Oracle identity domain.75- **[GitHub Actions](https://developers.openai.com/api/docs/guides/workload-identity-federation/github-actions)**: Use OIDC tokens in continuous integration workflows.76- **[SPIFFE](https://developers.openai.com/api/docs/guides/workload-identity-federation/spiffe)**: Use SPIFFE JWT-SVIDs issued by SPIRE or a compatible provider.77787980OpenAI supports OIDC-compatible JWT subject tokens in the documented81configurations, including SPIFFE JWT-SVIDs. For the OpenAI API, contact OpenAI82support if your OIDC provider isn't listed. For Codex, choose **Custom OIDC** in83the OpenAI Admin Portal.8485Each OIDC provider guide explains how to issue and inspect a token. For Codex,86follow only those token-issuance steps, then return to87[Use workload identity with Codex](#use-workload-identity-with-codex). The88guides' OpenAI setup and SDK examples apply to the OpenAI API path. X.50989federation supports the OpenAI API path only.9091## Use workload identity with the OpenAI API9293Use this path when your workload calls the OpenAI API directly. You need94permission to manage Workload Identity Providers and service account mappings95for the organization.9697Go to [Organization Settings > Security > Workload Identity Provider](https://platform.openai.com/settings/organization/security/workload-identity-provider).98Create the provider first, then configure its service account mappings from the99provider details page.100101### X.509 providers102103An X.509 provider derives workload identity attributes from a client certificate that OpenAI verifies against your organization's existing Mutual TLS configuration. It doesn't store certificates or maintain a separate trust store.104105Before creating the provider, configure and activate the trusted certificate106that anchors your client certificate in [Organization Settings > Security >107Mutual TLS](https://platform.openai.com/settings/organization/security/mtls).108The [Mutual TLS guide](https://developers.openai.com/api/docs/guides/mutual-tls) explains permissions,109certificate requirements, activation scope, mTLS hosts, certificate-chain110behavior, CEL filters, and rotation.111112Next, create the X.509 provider, derive one non-empty `openai.subject` value, and map that identity to a project service account with only the permissions the workload needs. The workload presents its certificate to the X.509 token endpoint to obtain a short-lived bearer token, then sends the bearer token and an accepted client certificate to the API mTLS endpoint.113114Follow the [X.509 certificate setup guide](https://developers.openai.com/api/docs/guides/workload-identity-federation/x509) for the complete dashboard and request flow.115116### Configure an OIDC Workload Identity Provider117118Create a Workload Identity Provider for each external issuer you trust. OpenAI119API workload identity supports OIDC JWT subject tokens. Its configuration120includes:121122| Option | Description |123| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |124| Name | A unique name for the Workload Identity Provider in your organization. |125| OIDC Issuer URL | The expected OIDC issuer URL. Issuer comparisons ignore a trailing slash. |126| Audience | The expected `aud` claim on the external subject token. |127| Description | Optional description for the Workload Identity Provider. |128| Use custom URL for OIDC discovery | When enabled, OpenAI fetches OIDC discovery metadata from a public HTTPS URL that can differ from the token issuer. |129| Custom OIDC discovery URL | The discovery base URL or complete `/.well-known/openid-configuration` URL used when custom discovery is enabled. |130| Use uploaded JWKS for token verification | When enabled, OpenAI verifies tokens against an uploaded JWKS instead of fetching keys from OIDC discovery. |131| JWKS JSON | The uploaded public JWKS object used when uploaded JWKS verification is enabled. The JWKS must contain a non-empty `keys` array and no private key material. |132| Attribute transformations | Optional CEL expressions that derive custom `openai.*` attributes from token claims for mapping decisions. |133134Custom OIDC discovery and uploaded JWKS are mutually exclusive. Enabling135custom discovery hides the uploaded JWKS option. The custom discovery URL must136use public HTTPS and cannot contain credentials, a custom port, a query, or a137fragment.138139If **Use custom URL for OIDC discovery** does not appear in your dashboard, use140standard OIDC discovery or enable **Use uploaded JWKS for token verification**141instead. Use the public JWKS published by your identity provider and update it142when the provider rotates its signing keys.143144When the token issuer and discovery host differ, set **OIDC Issuer URL** to the145token's `iss` claim and **Custom OIDC discovery URL** to the host that publishes146the provider's discovery document. OpenAI still checks the token against the147configured issuer; the custom URL only determines where it retrieves discovery148metadata and public signing keys.149150#### Transform token claims with CEL151152Attribute transformations use Common Expression Language (CEL). OpenAI153supports the standard CEL operators specified in154[langdef.md](https://github.com/google/cel-spec/blob/master/doc/langdef.md) and155doesn't add custom workload identity federation functions. Each expression156receives one root object:157158- `assertion`: The verified JWT claim set.159160The dashboard automatically applies the `openai.` prefix. Enter the161suffix, such as `subject`, and an expression, such as `assertion.sub`. The API162stores the derived attribute as `openai.subject`.163164```json165[166 {167 "attribute": "openai.subject",168 "expression": "assertion.sub"169 },170 {171 "attribute": "openai.repository",172 "expression": "assertion.repository"173 }174]175```176177Use CEL syntax defined by the CEL language specification. For example, you can178read claim values with expressions such as `assertion.sub` or179`assertion.repository`. Unsupported syntax or functions fail mapping180resolution.181182```json183[184 {185 "attribute": "openai.repository_ref",186 "expression": "assertion.repository + \"@\" + assertion.ref"187 },188 {189 "attribute": "openai.production",190 "expression": "assertion.ref == \"refs/heads/main\""191 }192]193```194195Transformation results must be scalar values: strings, `true` or `false`196values, integers, or finite numbers. Arrays, objects, null values, and197evaluation errors fail mapping resolution. OpenAI converts scalar198transformation results to strings before comparing them to mapping values. For199example, `true` becomes `"true"` and `7` becomes `"7"`.200201Mapping keys that start with `openai.` resolve only from attribute202transformations. Raw subject token claims that already use an `openai.` prefix203don't affect mapping decisions unless you configure a matching transformation.204205#### Manage JWKS and key rotation206207OpenAI verifies OIDC subject tokens with the key source configured on the208Workload Identity Provider:209210- **OIDC discovery:** OpenAI fetches the issuer's211 `/.well-known/openid-configuration`, then fetches the discovered `jwks_uri`.212 OpenAI caches discovery documents and remote JWKS payloads for 600 seconds.213- **Custom OIDC discovery:** OpenAI fetches214 `/.well-known/openid-configuration` from the configured custom discovery base215 URL, then fetches the discovered `jwks_uri`. The token's `iss` claim must216 still match **OIDC Issuer URL**.217- **Key refresh on miss:** If a token `kid` isn't found in the cached JWKS,218 OpenAI refreshes the JWKS and tries the lookup again before rejecting the219 token.220- **Uploaded JWKS:** When **Use uploaded JWKS for token verification** is221 enabled, OpenAI uses the uploaded JWKS stored on the provider and doesn't222 perform OIDC discovery or remote JWKS fetching. After a provider update is223 available to token exchange, new exchanges use the saved JWKS.224- **Key sets:** A JWKS can contain more than one public key. Each key must have a225 unique, non-empty `kid`.226227During signing-key rotation, publish both old and new public keys in the issuer228JWKS during the rotation window. This lets tokens signed by the old key keep229working while OpenAI accepts tokens signed by the new key. For uploaded JWKS,230update the provider before issuing tokens with the new `kid`; OpenAI rejects231tokens signed by a key absent from the configured JWKS.232233<a id="configure-service-account-mappings"></a>234235### Configure a service account mapping236237A service account mapping defines which external identities can mint access238tokens for an OpenAI service account.239240For X.509 providers, mapping keys use derived `openai.*` attributes. Prefer an241exact `openai.subject` mapping. Raw JWT claims such as `sub`, `aud`, and `iss`242apply only to OIDC providers.243244Its configuration includes:245246| Option | Description |247| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |248| Name | A unique name for the mapping within the Workload Identity Provider. |249| Key | The attribute key to match. Use a raw token claim, such as `sub`, `aud`, or `iss`, or a derived attribute like `openai.subject`. |250| Value | The attribute value that must match before OpenAI issues a token. |251| Description | Optional description for the mapping. |252| Project | The project that owns the target service account. |253| Service account | The service account the workload can use. You can create a new service account in the selected project or select an existing service account. |254| Permissions | Optional API permissions that further narrow access tokens minted from this mapping. These permissions can't grant access beyond the mapped service account. |255256Attribute values must be scalar JSON values. String values can use one trailing257wildcard with a non-empty prefix, such as `repo:example/*`. A wildcard by itself258or in the middle of a value isn't supported.259260Valid wildcard values:261262- `repo:openai/*`263- `repository:my-org/*`264265Unsupported wildcard values:266267- `*`268- `repo:*:prod`269- `repo/*/main`270271The dashboard shows mapping restrictions as **Permissions**. Token exchange272responses expose the same restrictions as OAuth scopes in the `scope`273property. Mappings can't include Admin API scopes, and normal downstream API274authorization still applies.275276#### Mapping resolution example277278Mapping resolution starts after OpenAI verifies the external identity.279OpenAI looks up mappings for the requested `identity_provider_id` and280`service_account_id`, skips mappings that aren't enabled, evaluates only the281attributes needed by each mapping, and issues a token only if exactly one282enabled mapping matches every configured attribute.283284Suppose a GitHub Actions token contains these claims:285286```json287{288 "iss": "https://token.actions.githubusercontent.com",289 "aud": "https://api.openai.com/v1",290 "sub": "repo:my-org/my-repo:ref:refs/heads/main",291 "repository": "my-org/my-repo",292 "ref": "refs/heads/main"293}294```295296The provider can derive an attribute:297298```json299[300 {301 "attribute": "openai.repository_ref",302 "expression": "assertion.repository + \"@\" + assertion.ref"303 }304]305```306307The service account mapping can then require both raw and derived attributes:308309| Key | Value |310| ----------------------- | --------------------------------------------- |311| `iss` | `https://token.actions.githubusercontent.com` |312| `sub` | `repo:my-org/my-repo:*` |313| `openai.repository_ref` | `my-org/my-repo@refs/heads/main` |314315All three values must match. The `sub` value uses a trailing wildcard, so it316matches any value with the prefix `repo:my-org/my-repo:`. The317`openai.repository_ref` key resolves from the attribute transformation, not a318raw token claim with that name.319320If more than one enabled mapping matches an exchange, OpenAI rejects it. OpenAI321enforces a unique mapping for each `(provider, service account)` pair and322doesn't combine permissions from different mappings.323324### Connect the workload325326Use the SDK example in your [identity-provider guide](#get-an-identity-token),327or call the token exchange endpoint directly. For request and response fields,328authorization behavior, and current limitations, see the329[workload identity token exchange reference](https://developers.openai.com/api/reference/workload-identity-federation).330331#### Renew the access token332333If you manage token exchange directly, keep `access_token` and `expires_at`334together when passing the credential from a token service to an application.335The `expires_at` field is an absolute UTC expiration expressed as a Unix336timestamp in seconds. Schedule renewal before that time, allowing for clock337differences and request latency.338339The `expires_in` field is the token's lifetime in seconds from issuance. For340example, a token issued at 12:00 UTC with `expires_in: 3600` expires at 13:00341UTC, even if another service receives it at 12:05 UTC. Transport and processing342time don't extend the token's lifetime. See the [response343fields](https://developers.openai.com/api/reference/workload-identity-federation#response) for details.344345Token exchange doesn't return a refresh token. To renew, repeat the exchange346with a valid external identity token or client certificate.347348## Use workload identity with Codex349350Use this path for trusted Codex automation in a managed ChatGPT workspace.351Codex maps the workload to a ChatGPT user or service account instead of an API352Platform service account.353354Codex workload identity federation is in beta and must be enabled for your355 workspace. To request access, contact your OpenAI representative or [OpenAI356 Support](https://help.openai.com/en/articles/6614161-how-can-i-contact-support).357358The [federation rule359reference](https://developers.openai.com/api/docs/guides/workload-identity-federation/federation-rules)360explains how one rule can accept more than one external subject while mapping to one361ChatGPT principal.362363## Troubleshoot a connection364365### OpenAI rejects the identity token366367Decode the token locally and compare its `iss`, `aud`, `sub`, `exp`, `iat`, and368provider-specific claims with the configured provider. Don't paste production369tokens into third-party JWT tools.370371For the OpenAI API, also compare the token attributes with the selected service372account mapping. For Codex, compare them with the selected federation rule.373374### The OpenAI API mapping doesn't match375376Confirm that the request uses the intended identity provider and service377account IDs, that the mapping is active, and that exactly one mapping matches.378See the [token exchange error reference](https://developers.openai.com/api/reference/workload-identity-federation#token-exchange-errors)379for detailed error categories.380381### Codex reports incomplete configuration382383Confirm that the Codex process has both required workload identity environment384variables and that `OPENAI_IDENTITY_TOKEN_FILE` contains an absolute path to a385current token. Check the file and parent-directory permissions.386387### Codex uses another credential388389Load both required workload identity variables into the Codex process. The390presence of either variable selects WIF ahead of API keys, access tokens, and391stored logins. Start a new process with the downloaded configuration loaded,392then run `codex login status` again.393394## Security recommendations395396- Use a dedicated principal for each application or workload.397- Separate production and non-production environments.398- Prefer exact claim matching over broad patterns.399- Grant only the access the workload needs.400- Use short access-token lifetimes.401- Review and remove unused providers, mappings, and rules.402- Review token exchange errors and unexpected access patterns.403404## Related docs405406- [Codex federation rule reference](https://developers.openai.com/api/docs/guides/workload-identity-federation/federation-rules)407- [Workload identity token exchange reference](https://developers.openai.com/api/reference/workload-identity-federation)408- [Codex authentication](https://developers.openai.com/codex/auth)409- [Codex environment variables](https://developers.openai.com/codex/config-file/environment-variables)410- [Codex non-interactive mode](https://developers.openai.com/codex/non-interactive-mode)