enterprise/workload-identity.md +0 −340 deleted
File Deleted View Diff
1# Workload identity federation
2
3> For the complete documentation index, see [llms.txt](https://learn.chatgpt.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.
4
5Workload identity federation lets trusted automation use Codex without storing
6a personal access token or another long-lived OpenAI credential. Your workload
7presents a short-lived identity token from a provider you already operate.
8OpenAI verifies that token and returns a short-lived access token for a user or
9service account in your managed ChatGPT workspace.
10
11Use workload identity for unattended Codex processes in cloud platforms,
12Kubernetes, CI systems, and other environments that can issue OIDC tokens or
13SPIFFE JWT-SVIDs. For the shared trust model and the separate OpenAI API flow,
14see the [workload identity overview](https://developers.openai.com/api/docs/guides/workload-identity-federation).
15
16Codex workload identity federation is in beta and must be enabled for your
17 workspace. To request access, contact your OpenAI representative or [OpenAI
18 Support](https://help.openai.com/en/articles/6614161-how-can-i-contact-support).
19
20## Before you begin
21
22You need:
23
24- Permission to manage workload identity in the OpenAI Admin Portal.
25- A managed ChatGPT workspace.
26- A ChatGPT user or service account that is an active member of that workspace,
27 or permission to create one during setup.
28- An OIDC token or SPIFFE JWT-SVID whose issuer, audience, and identifying
29 claims you know.
30- A runtime that can keep that token current in a protected file at an absolute
31 path.
32- Codex 0.148.0 or later.
33- An effective Codex authentication policy that permits ChatGPT authentication
34 and the workspace selected by the federation rule. See [Enforce a login
35 method or workspace](https://learn.chatgpt.com/docs/auth#enforce-a-login-method-or-workspace).
36
37OpenAI does not create a principal or workspace membership during token
38exchange. An administrator selects or creates the principal before the workload
39connects. Creating a human user consumes a workspace seat and follows the
40membership rules for that workspace.
41
42On native Windows, use the **elevated**
43[Windows sandbox](https://learn.chatgpt.com/docs/windows/windows-sandbox). Other Windows sandbox modes
44cannot protect the identity-token file from model-controlled commands.
45
46## Get an identity token
47
48Your workload runtime gets and refreshes the upstream identity token. Codex does
49not call cloud metadata services or identity-provider client libraries on your
50behalf.
51
52| Runtime | Recommended token-file source |
53| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
54| Kubernetes, AKS, EKS, or GKE | Mount a projected service-account token and point Codex at that file. The platform rotates it. |
55| Microsoft Entra managed identity | Run a trusted host process or sidecar that requests a token from Azure IMDS and replaces the file before expiry. |
56| AWS outbound identity federation | Run a trusted host process that calls regional STS `GetWebIdentityToken` and replaces the file before expiry. |
57| Google Cloud | Run a trusted host process that requests an identity token from the metadata server and replaces the file before expiry. |
58| Oracle Cloud Infrastructure | Run a trusted host process that uses an instance principal to request an IDCS access token and replaces the file before expiry. |
59| GitHub Actions | Request the job's OIDC token, write it to a protected file, and request a new token before a later exchange. |
60| SPIFFE | Use the SPIFFE Workload API or an approved helper to write a current JWT-SVID to the file. |
61| Custom OIDC provider | Use the issuer's workload flow to get a JWT, then refresh the protected file before the JWT expires. |
62
63Follow the guide for your provider to configure token issuance and inspect a
64sample token:
65
66- [Microsoft Azure](https://developers.openai.com/api/docs/guides/workload-identity-federation/microsoft-azure)
67- [AWS](https://developers.openai.com/api/docs/guides/workload-identity-federation/aws)
68- [Google Cloud](https://developers.openai.com/api/docs/guides/workload-identity-federation/google-cloud)
69- [Oracle Cloud Infrastructure](https://developers.openai.com/api/docs/guides/workload-identity-federation/oracle-cloud)
70- [GitHub Actions](https://developers.openai.com/api/docs/guides/workload-identity-federation/github-actions)
71- [Kubernetes](https://developers.openai.com/api/docs/guides/workload-identity-federation/kubernetes)
72- [SPIFFE](https://developers.openai.com/api/docs/guides/workload-identity-federation/spiffe)
73
74Decode a sample token locally and record its `iss`, `aud`, `sub`, and any other
75claims you plan to trust. Decoding does not verify the signature. Do not paste a
76production token into a website or write it to logs.
77
78## Connect the workload
79
80An administrator creates the provider and federation rule before starting
81Codex.
82
831. Open [Workload identity](https://admin.openai.com/workload-identity) in the
84 OpenAI Admin Portal, then select **Connect workload**.
852. Reuse a provider configured for Codex, or create one. Provider presets fill
86 in common settings for GitHub Actions, Microsoft Entra ID, Google Cloud,
87 AWS, Kubernetes, SPIFFE, and custom OIDC providers.
883. Select **Codex** and the managed workspace the workload may use.
894. Add the narrowest conditions that identify the workload. Match a subject,
90 exact claims, a CEL condition, or a combination. Add accepted audiences to
91 restrict which tokens the rule accepts. Every configured matcher must pass.
925. Map the rule to one existing ChatGPT user or service account, or create one
93 during setup.
946. Review the provider, conditions, workspace, principal, scopes, and access
95 token lifetime. Select **Connect workload**, then **Download config**.
96
97The downloaded file contains a non-secret federation rule ID and the path where
98Codex will read the identity token. It does not contain a credential.
99
100To automate setup, use the [workload identity Admin
101API](https://developers.openai.com/api/docs/guides/workload-identity-federation/admin-api). For matcher
102behavior and examples, see [Federation rule
103reference](https://developers.openai.com/api/docs/guides/workload-identity-federation/federation-rules).
104
105## Configure the Codex process
106
107The process that starts Codex requires these two workload identity variables:
108
109```bash
110export OPENAI_FEDERATION_RULE_ID="idpm_..."
111export OPENAI_IDENTITY_TOKEN_FILE="/var/run/secrets/openai.com/identity-token"
112```
113
114`OPENAI_FEDERATION_RULE_ID` is not a secret. The token file is. Use an absolute
115path in a dedicated directory, such as `/var/run/secrets/openai.com`, owned by
116the workload account with mode `0700`. Only trusted host processes should write
117there. Keep the directory outside repositories and other paths available to
118Codex tools. Keep credentials out of logs, shell history, and build artifacts.
119
120### Add audit attribution
121
122When runtime instances share a federation rule, you can identify each instance
123in token-issuance audit events. Set the optional
124`OPENAI_WORKLOAD_IDENTITY_CONTEXT` variable to a JSON object encoded as a
125string:
126
127```bash
128export OPENAI_WORKLOAD_IDENTITY_CONTEXT='{
129 "instance_id": "runner-42",
130 "display_name": "payments-prod",
131 "labels": {
132 "environment": "production",
133 "region": "us-west-2"
134 }
135}'
136```
137
138The object requires `instance_id`. It can also contain `display_name` and up to
139eight labels. The encoded object can be up to 1,024 bytes. `instance_id` and
140`display_name` can be up to 128 characters. Label keys can be up to 64
141characters, and label values can be up to 256 characters.
142
143Identifiers must start with an ASCII letter or number. Values can then contain
144letters, numbers, `.`, `_`, `:`, `/`, `@`, and `-`. Label keys support letters,
145numbers, `.`, `_`, and `-`.
146
147OpenAI treats this context as client-reported audit attribution, not as verified
148workload identity. It does not affect authentication, authorization, rule
149matching, scopes, rate limits, revocation, feature gates, or metrics. Do not put
150credentials, secrets, personal data, prompts, model output, or other Customer
151Content in it.
152
153For valid context, OpenAI derives a stable attribution ID scoped to the tenant,
154provider, federation rule, and `instance_id`. For attribution, the access token
155contains the ID but not the context. The successful token-issuance audit event
156contains the ID and the normalized context. Context that exceeds a limit or
157violates this schema makes the exchange fail with `invalid_grant`.
158
159Codex reads the context when the process starts and does not pass it, the rule
160ID, or the token-file path to model-controlled shells, hooks, or MCP servers.
161Restart Codex after changing the context.
162
163### Protect and rotate the token file
164
165For managed Linux, macOS, and WSL deployments, add the entire token directory to
166[`permissions.filesystem.deny_read`](https://learn.chatgpt.com/docs/enterprise/managed-configuration#enforce-deny-read-requirements)
167in managed requirements:
168
169```toml
170[permissions.filesystem]
171deny_read = ["/var/run/secrets/openai.com"]
172```
173
174This blocks model-controlled commands from reading the active token or a
175temporary replacement while the Codex host process can still use the token for
176exchange. For projected-token volumes, deny the entire token mount and any
177backing or resolved target paths outside it. File modes and environment-variable
178scrubbing alone do not protect credentials from another process running as the
179same user. On native Windows, use the elevated sandbox described above.
180
181For token sources that do not project a file, have a trusted host process write
182each replacement inside that protected directory and rename it into place. An
183atomic rename prevents Codex from reading a partial token. For example, adapt
184this host-owned refresh script to your provider's token command. Provision the
185directory before running the script:
186
187```bash
188set -eu
189TOKEN_DIR="/var/run/secrets/openai.com"
190TOKEN_FILE="$TOKEN_DIR/identity-token"
191umask 077
192TOKEN_TEMP="$(mktemp "$TOKEN_DIR/.identity-token.XXXXXX")"
193trap 'rm -f -- "$TOKEN_TEMP"' EXIT
194trap 'exit 1' HUP INT TERM
195your-identity-provider-command > "$TOKEN_TEMP"
196test -s "$TOKEN_TEMP"
197mv -f -- "$TOKEN_TEMP" "$TOKEN_FILE"
198```
199
200Run the refresh process outside any shell or tool that Codex can control. Keep
201the read denial in place during refresh and cleanup. Even if a forced stop
202leaves a temporary file behind, that file must remain inside the denied
203directory. Do not put workload identity settings in `config.toml`.
204
205## Verify the connection
206
207Load the downloaded environment and inspect the selected authentication method:
208
209```bash
210. ./workload-identity-idpm_example.env
211codex login status
212```
213
214In PowerShell:
215
216```powershell
217$env:OPENAI_FEDERATION_RULE_ID = "idpm_..."
218$env:OPENAI_IDENTITY_TOKEN_FILE = "C:\run\openai\identity-token"
219codex login status
220```
221
222A successful check prints `Logged in using workload identity`. This confirms
223that Codex exchanged a token through the configured federation rule. The command
224does not print the resolved workspace, principal, or rule. Confirm those values
225in the Admin Portal before you start the workload. If Codex reports another
226authentication method, the two required WIF variables did not reach the process.
227
228If the provider uses **Prevent assertion replay** and the assertion has a `jti`
229claim, this check consumes that `jti`. Write a newly issued assertion with a new
230`jti` before starting another Codex process.
231
232Run a small request from the same environment:
233
234```bash
235codex exec "Reply with only: workload identity is working"
236```
237
238Codex exchanges the upstream token and keeps the OpenAI access token in memory.
239It does not write either credential to `auth.json`, the system keyring, or
240`config.toml`.
241
242## Keep the token current
243
244Refresh the identity-token file before the upstream token expires. Codex rereads
245the file when it needs another OpenAI access token. The OpenAI token expires at
246the earlier of the upstream token's expiry or the federation rule's lifetime,
247and never lasts longer than one hour.
248
249When an administrator turns on replay protection, each upstream JWT must have a
250unique `jti`. Write a newly issued assertion with a new `jti` before each
251exchange, including refreshes in a long-running process. Assertions without
252`jti` do not receive replay protection.
253
254Codex shares one in-memory exchange session inside each host process. Concurrent
255requests in that process reuse a valid OpenAI access token and share one refresh
256when it expires. Separate processes perform separate exchanges, so they need
257assertions that the provider permits them to use.
258
259## Credential precedence
260
261The two required workload identity variables take precedence over every other
262credential source:
263
2641. If either `OPENAI_FEDERATION_RULE_ID` or
265 `OPENAI_IDENTITY_TOKEN_FILE` is present, Codex selects workload identity.
2662. If only one required variable is present, Codex returns an error. It does not
267 fall back to an API key, access token, or stored login.
2683. `OPENAI_WORKLOAD_IDENTITY_CONTEXT` alone does not select workload identity.
2694. When neither required WIF variable is present, Codex applies the normal
270 credential rules for that surface. For surfaces that allow API key
271 authentication, `CODEX_API_KEY` takes precedence on `codex exec`,
272 `codex review`, the TypeScript SDK, and `codex exec-server --remote`. Other
273 surfaces can use `CODEX_ACCESS_TOKEN` or a stored login.
274
275An SDK `apiKey` option becomes `CODEX_API_KEY`, but WIF still takes precedence
276when either required WIF variable is present. Omit the option when using WIF so
277the workload does not carry an unused long-lived credential.
278
279To move an existing workload without downtime, configure WIF while its current
280credential is still available. Start a new process with both required WIF
281variables; WIF takes precedence even if the old credential is still present.
282After the workload succeeds with WIF, remove the old credential from its runtime
283and secrets store, then revoke it. Before revocation, you can roll back by
284removing both required WIF variables and starting a new process.
285
286## Supported Codex surfaces
287
288Configure workload identity on the machine that owns the Codex process.
289
290| Surface | Support and host boundary |
291| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
292| Interactive `codex`, `resume`, and `fork` | Supported. Start the CLI in the configured environment. |
293| `codex exec`, `exec resume`, and `codex review` | Supported. Either required WIF variable makes WIF take precedence. |
294| TypeScript SDK | Supported. The parent process supplies the required WIF variables and any optional attribution context. |
295| `codex app-server` | Supported. Configure WIF on the app-server host, not on a remote client. |
296| `codex exec-server --remote` | Supported for authentication to the remote environment registry. Configure WIF on the exec-server host. |
297| Local exec-server process operations | Do not use WIF authentication. They run through the local exec-server protocol. |
298
299Remote app-server and exec-server clients never send the upstream identity
300token over their protocols.
301
302## Change or remove access
303
304Changes to a rule's subjects, audiences, claims, CEL condition, scopes, or token
305lifetime apply to new exchanges. A token issued before the change can remain
306valid until its lifetime ends.
307
308Disable a provider or rule to stop access immediately. Disablement blocks new
309exchanges and revokes OpenAI access tokens already issued through that resource.
310Archiving has the same access effect and cannot be undone. Changing provider
311trust also revokes issued tokens before the new trust takes effect.
312
313## Audit changes
314
315Provider and federation rule creation, updates, and archival generate audit
316events. Use the [Compliance API and audit event
317guidance](https://learn.chatgpt.com/docs/enterprise/compliance-api) to export the events your workspace
318supports. Correlate them with your identity provider's issuance logs, and do not
319record upstream assertions or OpenAI access tokens in either system.
320
321When the process supplies `OPENAI_WORKLOAD_IDENTITY_CONTEXT`, successful
322token-issuance audit events also contain the stable attribution ID and
323normalized context described above.
324
325## Troubleshoot
326
327| Symptom | Check |
328| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
329| Codex reports incomplete workload identity configuration | Set both required variables in the same process and use an absolute token-file path. |
330| Codex reports that its login policy does not permit workload identity | Allow ChatGPT authentication in the effective policy and include the rule's workspace in its permitted workspaces. |
331| Codex reports another credential | Load both required WIF variables into the Codex process, then start a new process and rerun `codex login status`. |
332| OpenAI rejects workload context | Check its JSON shape, size, allowed characters, and field limits. Remove sensitive or Customer Content. |
333| OpenAI rejects the token | Compare `iss`, `aud`, expiry, signature key, and assertion lifetime with the provider configuration. |
334| The rule does not match | Confirm the client uses the intended rule ID and that every subject, audience, exact-claim, and CEL check passes. |
335| OpenAI rejects the principal | Confirm the user or service account is active and is an active member of the selected workspace. |
336| OpenAI rejects a repeated assertion | Get a new JWT with a new `jti`; do not retry the same replay-protected assertion. |
337| A long-running process stops refreshing | Confirm the host refresh process is still replacing the token file before expiry. |
338
339For provider verification, limits, and CEL details, see the [federation rule
340reference](https://developers.openai.com/api/docs/guides/workload-identity-federation/federation-rules).