Skip to content

feat: load AgentIdentity from JWT login/env#18904

Merged
shijie-oai merged 2 commits intomainfrom
dev/efrazer/agent-identity-env-jwt
Apr 26, 2026
Merged

feat: load AgentIdentity from JWT login/env#18904
shijie-oai merged 2 commits intomainfrom
dev/efrazer/agent-identity-env-jwt

Conversation

@efrazer-oai
Copy link
Copy Markdown
Contributor

@efrazer-oai efrazer-oai commented Apr 21, 2026

Summary

This PR lets programmatic AgentIdentity users provide one token through either stdin login or environment auth.

codex login --with-agent-identity reads an Agent Identity JWT from stdin, validates that it has the required claims, and stores that token as the agent_identity value in auth.json. The file format is token-only; the decoded account and key fields are runtime state, not hand-authored auth.json fields.

The Agent Identity JWT claim shape and decoder live in codex-agent-identity; codex-login only owns env/storage precedence and conversion into CodexAuth::AgentIdentity.

When env auth is enabled, CODEX_AGENT_IDENTITY can provide the same JWT without writing auth state to disk. CODEX_API_KEY still wins if both env vars are set.

Reference old stack: https://github.com/openai/codex/pull/17387/changes
Reference JWT/env stack: #18176

Stack

  1. fix: fully revert agent identity runtime wiring #18757: full revert
  2. refactor: add agent identity crate #18871: isolated Agent Identity crate
  3. feat: add explicit AgentIdentity auth mode #18785: explicit AgentIdentity auth mode and startup task allocation
  4. refactor: route Codex auth through AuthProvider #18811: migrate Codex backend auth callsites through AuthProvider
  5. This PR: accept AgentIdentity JWTs through login/env

Testing

Tests: targeted login and Agent Identity crate tests, CLI checks, scoped formatter/linter cleanup, and CI.

@efrazer-oai efrazer-oai requested a review from pakrym-oai April 21, 2026 23:13
@efrazer-oai efrazer-oai marked this pull request as ready for review April 21, 2026 23:13
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from db51937 to f15803b Compare April 21, 2026 23:19
@efrazer-oai efrazer-oai requested a review from a team as a code owner April 21, 2026 23:19
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from ca0aeac to 0d52d99 Compare April 21, 2026 23:21
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

fn resolved_mode(&self) -> ApiAuthMode {
if let Some(mode) = self.auth_mode {
return mode;
}
if self.openai_api_key.is_some() {
return ApiAuthMode::ApiKey;
}
ApiAuthMode::Chatgpt

P1 Badge Infer AgentIdentity mode when agent_identity is present

The new JWT/object deserialization for auth.json.agent_identity is ineffective unless auth_mode is also set, because resolved_mode() ignores agent_identity. A JWT-only auth.json falls back to Chatgpt mode and later behaves as missing token auth, which contradicts the “paste one token into auth.json” flow introduced here.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from f15803b to ae57449 Compare April 21, 2026 23:52
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from 0d52d99 to 455f6d5 Compare April 21, 2026 23:54
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch 2 times, most recently from ec85840 to d343533 Compare April 22, 2026 01:04
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from 455f6d5 to fdfad31 Compare April 22, 2026 01:06
@efrazer-oai
Copy link
Copy Markdown
Contributor Author

💡 Codex Review

fn resolved_mode(&self) -> ApiAuthMode {
if let Some(mode) = self.auth_mode {
return mode;
}
if self.openai_api_key.is_some() {
return ApiAuthMode::ApiKey;
}
ApiAuthMode::Chatgpt

P1 Badge Infer AgentIdentity mode when agent_identity is present
The new JWT/object deserialization for auth.json.agent_identity is ineffective unless auth_mode is also set, because resolved_mode() ignores agent_identity. A JWT-only auth.json falls back to Chatgpt mode and later behaves as missing token auth, which contradicts the “paste one token into auth.json” flow introduced here.

ℹ️ About Codex in GitHub

Disagree here, we should absolutely set auth_mode if we're copy-pasting in auth.json as the structure is tagged. If we're doing env variable, we don't break.

@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from d343533 to 74c78b4 Compare April 22, 2026 01:10
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from fdfad31 to a87f5e0 Compare April 22, 2026 01:10
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from 74c78b4 to ae23fca Compare April 22, 2026 01:13
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from a87f5e0 to b7a4275 Compare April 22, 2026 01:13
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from ae23fca to bccee32 Compare April 22, 2026 01:19
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from b7a4275 to 7bbbecd Compare April 22, 2026 01:19
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from bccee32 to 160793a Compare April 22, 2026 01:23
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from 7bbbecd to c305e9e Compare April 22, 2026 01:24
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from 160793a to df5a2df Compare April 22, 2026 01:37
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from c305e9e to 8afc806 Compare April 22, 2026 01:38
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from df5a2df to ed51cb2 Compare April 22, 2026 01:41
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from 8afc806 to f195c46 Compare April 22, 2026 01:41
Comment thread codex-rs/login/src/auth/storage.rs Outdated
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_agent_identity"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we not storing in a consistent format?

Comment thread codex-rs/login/src/auth/storage.rs Outdated
}

#[derive(Deserialize)]
struct AgentIdentityJwtClaims {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this go into agent identity crate?

@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch 2 times, most recently from 6a26704 to 1a81344 Compare April 22, 2026 16:43
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from 6c03831 to 3bb786d Compare April 22, 2026 17:07
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from 1a81344 to 466cce8 Compare April 22, 2026 17:07
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from 3bb786d to 27d0647 Compare April 22, 2026 17:31
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch 2 times, most recently from 2038a7a to dc284bd Compare April 22, 2026 20:25
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from aa31e4b to b0017b5 Compare April 22, 2026 20:54
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch 2 times, most recently from c588673 to c74a2f3 Compare April 22, 2026 23:57
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch from d339b11 to ece4453 Compare April 23, 2026 01:54
morozow pushed a commit to morozow/codex that referenced this pull request Apr 23, 2026
## Summary

This PR adds `codex-agent-identity` as an isolated crate for Agent
Identity business logic.

The crate owns:
- AgentAssertion construction.
- Agent task registration.
- private-key assertion signing.
- bounded blocking HTTP for task registration.

It does not wire AgentIdentity into `auth.json`, `AuthManager`, rollout
state, or request callsites. That integration happens in later PRs.

Reference old stack: https://github.com/openai/codex/pull/17387/changes

## Stack

1. openai#18757: full revert
2. This PR: isolated Agent Identity crate
3. openai#18785: explicit AgentIdentity
auth mode and startup task allocation
4. openai#18811: migrate Codex backend
auth callsites through AuthProvider
5. openai#18904: accept AgentIdentity JWTs
and load `CODEX_AGENT_IDENTITY`

## Testing

Tests: targeted Rust checks, cargo-shear, Bazel lock check, and CI.
morozow pushed a commit to morozow/codex that referenced this pull request Apr 23, 2026
## Summary

This PR adds `CodexAuth::AgentIdentity` as an explicit auth mode.

An AgentIdentity auth record is a standalone `auth.json` mode. When
`AuthManager::auth().await` loads that mode, it registers one
process-scoped task and stores it in runtime-only state on the auth
value. Header creation stays synchronous after that because the task is
initialized before callers receive the auth object.

This PR also removes the old feature flag path. AgentIdentity is
selected by explicit auth mode, not by a hidden flag or lazy mutation of
ChatGPT auth records.

Reference old stack: https://github.com/openai/codex/pull/17387/changes

## Design Decisions

- AgentIdentity is a real auth enum variant because it can be the only
credential in `auth.json`.
- The process task is ephemeral runtime state. It is not serialized and
is not stored in rollout/session data.
- Account/user metadata needed by existing Codex backend checks lives on
the AgentIdentity record for now.
- `is_chatgpt_auth()` remains token-specific.
- `uses_codex_backend()` is the broader predicate for ChatGPT-token auth
and AgentIdentity auth.

## Stack

1. openai#18757: full revert
2. openai#18871: isolated Agent Identity
crate
3. This PR: explicit AgentIdentity auth mode and startup task allocation
4. openai#18811: migrate Codex backend
auth callsites through AuthProvider
5. openai#18904: accept AgentIdentity JWTs
and load `CODEX_AGENT_IDENTITY`

## Testing

Tests: targeted Rust checks, cargo-shear, Bazel lock check, and CI.
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-auth-callers branch 2 times, most recently from 213fff4 to 72fe598 Compare April 23, 2026 22:44
efrazer-oai added a commit that referenced this pull request Apr 24, 2026
## Summary

This PR moves Codex backend request authentication from direct
bearer-token handling to `AuthProvider`.

The new `codex-auth-provider` crate defines the shared request-auth
trait. `CodexAuth::provider()` returns a provider that can apply all
headers needed for the selected auth mode.

This lets ChatGPT token auth and AgentIdentity auth share the same
callsite path:
- ChatGPT token auth applies bearer auth plus account/FedRAMP headers
where needed.
- AgentIdentity auth applies AgentAssertion plus account/FedRAMP headers
where needed.

Reference old stack: https://github.com/openai/codex/pull/17387/changes

## Callsite Migration

| Area | Change |
| --- | --- |
| backend-client | accepts an `AuthProvider` instead of a raw
token/header |
| chatgpt client/connectors | applies auth through
`CodexAuth::provider()` |
| cloud tasks | keeps Codex-backend gating, applies auth through
provider |
| cloud requirements | uses Codex-backend auth checks and provider
headers |
| app-server remote control | applies provider headers for backend calls
|
| MCP Apps/connectors | gates on `uses_codex_backend()` and keys caches
from generic account getters |
| model refresh | treats AgentIdentity as Codex-backend auth |
| OpenAI file upload path | rejects non-Codex-backend auth before
applying headers |
| core client setup | keeps model-provider auth flow and allows
AgentIdentity through provider-backed OpenAI auth |

## Stack

1. #18757: full revert
2. #18871: isolated Agent Identity
crate
3. #18785: explicit AgentIdentity
auth mode and startup task allocation
4. This PR: migrate Codex backend auth callsites through AuthProvider
5. #18904: accept AgentIdentity JWTs
and load `CODEX_AGENT_IDENTITY`

## Testing

Tests: targeted Rust checks, cargo-shear, Bazel lock check, and CI.
Base automatically changed from dev/efrazer/agent-identity-auth-callers to main April 24, 2026 00:14
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch 2 times, most recently from 868e900 to 8d2470f Compare April 25, 2026 00:53
@efrazer-oai efrazer-oai force-pushed the dev/efrazer/agent-identity-env-jwt branch from 8d2470f to c5d5e7c Compare April 25, 2026 01:45
## Summary
- decode unsigned agent identity JWT payloads from the web UI format
- register agent identity tasks through the production AuthAPI accounts
base URL
- skip cloud requirement fetches for agent identity auth
- improve task registration error details

## Validation
- `cargo fmt --check`
- `cargo test -p codex-login agent_identity --lib`
- `cargo build --bin codex`
- local smoke test with `OPENAI_API_KEY` and `CODEX_API_KEY` unset,
`CODEX_AGENT_IDENTITY="$CDOEX_TEST_AGENT_IDENTITY"`, and
`target/debug/codex exec --skip-git-repo-check --ephemeral "Say exactly:
agent identity smoke test ok"`

The latest smoke on the squashed commit connected to
`wss://chatgpt.com/backend-api/codex/responses` and returned `agent
identity smoke test ok`, confirming the agent identity inference path
works end to end. Startup side requests for plugins/models/analytics
still show 401s under agent identity, but they did not block the
inference path.
@shijie-oai shijie-oai enabled auto-merge (squash) April 26, 2026 19:40
@shijie-oai shijie-oai disabled auto-merge April 26, 2026 19:42
@shijie-oai shijie-oai enabled auto-merge (squash) April 26, 2026 19:46
@shijie-oai shijie-oai merged commit fed0a8f into main Apr 26, 2026
25 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants