mirror of
https://github.com/openai/codex.git
synced 2026-11-14 06:48:26 +00:00
core: support dynamic auth tokens for model providers (#16288)
## Summary Fixes #15189. Custom model providers that set `requires_openai_auth = false` could only use static credentials via `env_key` or `experimental_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 a `401`. This PR adds that provider config and wires it through the existing auth design: request paths still go through `AuthManager.auth()` and `UnauthorizedRecovery`, with `core` only choosing when to use a provider-backed bearer-only `AuthManager`. ## Scope To keep this PR reviewable, `/models` only uses provider auth for the initial request in this change. It does **not** add a dedicated `401` retry path for `/models`; that can be follow-up work if we still need it after landing the main provider-token support. ## Example Usage ```toml model_provider = "corp-openai" [model_providers.corp-openai] name = "Corp OpenAI" base_url = "https://gateway.example.com/openai" requires_openai_auth = false [model_providers.corp-openai.auth] command = "gcloud" args = ["auth", "print-access-token"] timeout_ms = 5000 refresh_interval_ms = 300000 ``` The command contract is intentionally small: - write the bearer token to `stdout` - exit `0` - any leading or trailing whitespace is trimmed before the token is used ## What Changed - add `model_providers.<id>.auth` to the config model and generated schema - validate that command-backed provider auth is mutually exclusive with `env_key`, `experimental_bearer_token`, and `requires_openai_auth` - build a bearer-only `AuthManager` for `ModelClient` and `ModelsManager` when a provider configures `auth` - let normal Responses requests and realtime websocket connects use the provider-backed bearer source through the same `AuthManager.auth()` path - allow `/models` online refresh for command-auth providers and attach the provider token to the initial `/models` request - keep `auth.cwd` available as an advanced escape hatch and include it in the generated config schema ## Testing - `cargo test -p codex-core provider_auth_command` - `cargo test -p codex-core refresh_available_models_uses_provider_auth_token` - `cargo test -p codex-core test_deserialize_provider_auth_config_defaults` ## Docs - `developers.openai.com/codex` should document the new `[model_providers.<id>.auth]` block and the token-command contract
This commit is contained in:
1 parent
0071968829
commit
20f43c1e05
17 files changed
+598
-4
No files matched your search
@@ -0,0 +1,31 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::AuthManager;
|
||||
use crate::model_provider_info::ModelProviderInfo;
|
||||
|
||||
/// Returns the provider-scoped auth manager when this provider uses command-backed auth.
|
||||
///
|
||||
/// Providers without custom auth continue using the caller-supplied base manager.
|
||||
pub(crate) fn auth_manager_for_provider(
|
||||
auth_manager: Option<Arc<AuthManager>>,
|
||||
provider: &ModelProviderInfo,
|
||||
) -> Option<Arc<AuthManager>> {
|
||||
match provider.auth.clone() {
|
||||
Some(config) => Some(AuthManager::external_bearer_only(config)),
|
||||
None => auth_manager,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an auth manager for request paths that always require authentication.
|
||||
///
|
||||
/// Providers with command-backed auth get a bearer-only manager; otherwise the caller's manager
|
||||
/// is reused unchanged.
|
||||
pub(crate) fn required_auth_manager_for_provider(
|
||||
auth_manager: Arc<AuthManager>,
|
||||
provider: &ModelProviderInfo,
|
||||
) -> Arc<AuthManager> {
|
||||
match provider.auth.clone() {
|
||||
Some(config) => AuthManager::external_bearer_only(config),
|
||||
None => auth_manager,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user