Conversation
This was referenced Mar 31, 2026
f042fd7 to
0b30a7a
Compare
bolinfest
added a commit
that referenced
this pull request
Mar 31, 2026
## Summary `ExternalAuthRefresher` was still shaped around external ChatGPT auth: `ExternalAuthTokens` always implied ChatGPT account metadata even when a caller only needed a bearer token. This PR generalizes that contract so bearer-only sources are first-class, while keeping the existing ChatGPT paths strict anywhere we persist or rebuild ChatGPT auth state. ## Motivation This is the first step toward #15189. The follow-on provider-auth work needs one shared external-auth contract that can do both of these things: - resolve the current bearer token before a request is sent - return a refreshed bearer token after a `401` That should not require a second token result type just because there is no ChatGPT account metadata attached. ## What Changed - change `ExternalAuthTokens` to carry `access_token` plus optional `ExternalAuthChatgptMetadata` - add helper constructors for bearer-only tokens and ChatGPT-backed tokens - add `ExternalAuthRefresher::resolve()` with a default no-op implementation so refreshers can optionally provide the current token before a request is sent - keep ChatGPT-only persistence strict by continuing to require ChatGPT metadata anywhere the login layer seeds or reloads ChatGPT auth state - update the app-server bridge to construct the new token shape for external ChatGPT auth refreshes ## Testing - `cargo test -p codex-login` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16286). * #16288 * #16287 * __->__ #16286
2bb3ea6 to
e13e00c
Compare
bolinfest
added a commit
that referenced
this pull request
Mar 31, 2026
## Summary `AuthManager` and `UnauthorizedRecovery` already own token resolution and staged `401` recovery. The missing piece for provider auth was a bearer-only mode that still fit that design, instead of pushing a second auth abstraction into `codex-core`. This PR keeps the design centered on `AuthManager`: it teaches `codex-login` how to own external bearer auth directly so later provider work can keep calling `AuthManager.auth()` and `UnauthorizedRecovery`. ## Motivation This is the middle layer for #15189. The intended design is still: - `AuthManager` encapsulates token storage and refresh - `UnauthorizedRecovery` powers staged `401` recovery - all request tokens go through `AuthManager.auth()` This PR makes that possible for provider-backed bearer tokens by adding a bearer-only auth mode inside `AuthManager` instead of building parallel request-auth plumbing in `core`. ## What Changed - move `ModelProviderAuthInfo` into `codex-protocol` so `core` and `login` share one config shape - add `login/src/auth/external_bearer.rs`, which runs the configured command, caches the bearer token in memory, and refreshes it after `401` - add `AuthManager::external_bearer_only(...)` for provider-scoped request paths that should use command-backed bearer auth without mutating the shared OpenAI auth manager - add `AuthManager::shared_with_external_chatgpt_auth_refresher(...)` and rename the other `AuthManager` helpers that only apply to external ChatGPT auth so the ChatGPT-only path is explicit at the call site - keep external ChatGPT refresh behavior unchanged while ensuring bearer-only external auth never persists to `auth.json` ## Testing - `cargo test -p codex-login` - `cargo test -p codex-protocol` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16287). * #16288 * __->__ #16287
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #15189.
Custom model providers that set
requires_openai_auth = falsecould only use static credentials viaenv_keyorexperimental_bearer_token. That is not enough for providers that mint short-lived bearer tokens, because Codex had no way to run a command to obtain a bearer token, cache it briefly in memory, and retry with a refreshed token after a401.This PR adds that provider config and wires it through the existing auth design: request paths still go through
AuthManager.auth()andUnauthorizedRecovery, withcoreonly choosing when to use a provider-backed bearer-onlyAuthManager.Scope
To keep this PR reviewable,
/modelsonly uses provider auth for the initial request in this change. It does not add a dedicated401retry path for/models; that can be follow-up work if we still need it after landing the main provider-token support.Example Usage
The command contract is intentionally small:
stdout0What Changed
model_providers.<id>.authto the config model and generated schemaenv_key,experimental_bearer_token, andrequires_openai_authAuthManagerforModelClientandModelsManagerwhen a provider configuresauthAuthManager.auth()path/modelsonline refresh for command-auth providers and attach the provider token to the initial/modelsrequestauth.cwdavailable as an advanced escape hatch and include it in the generated config schemaTesting
cargo test -p codex-core provider_auth_commandcargo test -p codex-core refresh_available_models_uses_provider_auth_tokencargo test -p codex-core test_deserialize_provider_auth_config_defaultsDocs
developers.openai.com/codexshould document the new[model_providers.<id>.auth]block and the token-command contract