Honor configured proxy routes for auth refreshes (#34655)

## Why

ChatGPT token refresh requests need to follow the same configured routing policy as other authentication traffic, including environments that use the system proxy.

## What changed

- Require an `AuthRouteConfig` throughout login, logout, token refresh, personal access token, and agent identity flows.
- Build auth HTTP clients directly from that configuration instead of falling back to a default HTTP client when routing configuration is absent.

## Testing

- Add an integration test that refreshes a token through a cached system-proxy route and verifies the proxy receives the expected request.

GitOrigin-RevId: 7d54ab3219939a49921c51faf08cd4c2eabca51c
This commit is contained in:
Michael Bolin
2026-07-22 02:26:16 +00:00
committed by copyberry
parent 1823c13771
commit d4fcb2873b
24 changed files with 281 additions and 127 deletions
@@ -464,7 +464,7 @@ impl AccountRequestProcessor {
config.forced_chatgpt_workspace_id.clone(),
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
Some(config.auth_route_config()),
config.auth_route_config(),
)
};
#[cfg(debug_assertions)]
+12 -12
View File
@@ -120,7 +120,7 @@ async fn clear_existing_auth_before_login(
codex_home: &Path,
auth_credentials_store_mode: AuthCredentialsStoreMode,
auth_keyring_backend_kind: AuthKeyringBackendKind,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) {
if let Err(err) = logout_with_revoke(
codex_home,
@@ -139,13 +139,13 @@ pub async fn login_with_chatgpt(
forced_chatgpt_workspace_id: Option<Vec<String>>,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode,
auth_keyring_backend_kind: AuthKeyringBackendKind,
auth_route_config: Option<AuthRouteConfig>,
auth_route_config: AuthRouteConfig,
) -> std::io::Result<()> {
clear_existing_auth_before_login(
&codex_home,
cli_auth_credentials_store_mode,
auth_keyring_backend_kind,
auth_route_config.as_ref(),
&auth_route_config,
)
.await;
@@ -180,7 +180,7 @@ pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) ->
forced_chatgpt_workspace_id,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
Some(config.auth_route_config()),
config.auth_route_config(),
)
.await
{
@@ -246,7 +246,7 @@ pub async fn run_login_with_access_token(
config.forced_chatgpt_workspace_id.as_deref(),
Some(&config.chatgpt_base_url),
config.auth_keyring_backend_kind(),
Some(&auth_route_config),
&auth_route_config,
)
.await
{
@@ -320,7 +320,7 @@ pub async fn run_login_with_device_code(
&config.codex_home,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
Some(&auth_route_config),
&auth_route_config,
)
.await;
let forced_chatgpt_workspace_id = config.forced_chatgpt_workspace_id.clone();
@@ -330,7 +330,7 @@ pub async fn run_login_with_device_code(
forced_chatgpt_workspace_id,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
Some(auth_route_config),
auth_route_config,
);
if let Some(iss) = issuer_base_url {
opts.issuer = iss;
@@ -368,7 +368,7 @@ pub async fn run_login_with_device_code_fallback_to_browser(
&config.codex_home,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
Some(&auth_route_config),
&auth_route_config,
)
.await;
@@ -379,7 +379,7 @@ pub async fn run_login_with_device_code_fallback_to_browser(
forced_chatgpt_workspace_id,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
Some(auth_route_config),
auth_route_config,
);
if let Some(iss) = issuer_base_url {
opts.issuer = iss;
@@ -430,7 +430,7 @@ pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! {
config.cli_auth_credentials_store_mode,
Some(&config.chatgpt_base_url),
config.auth_keyring_backend_kind(),
Some(&auth_route_config),
&auth_route_config,
)
.await
{
@@ -484,7 +484,7 @@ pub async fn run_logout(cli_config_overrides: CliConfigOverrides) -> ! {
&config.codex_home,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
Some(&auth_route_config),
&auth_route_config,
)
.await
{
@@ -557,7 +557,7 @@ mod tests {
codex_home.path(),
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await;
+1 -1
View File
@@ -1756,7 +1756,7 @@ async fn load_exec_server_remote_auth_provider(
let auth = CodexAuth::from_agent_identity_jwt(
&agent_identity_jwt,
Some(&config.chatgpt_base_url),
Some(&auth_route_config),
&auth_route_config,
)
.await?;
return Ok(codex_model_provider::auth_provider_from_auth(&auth));
+1 -1
View File
@@ -610,7 +610,7 @@ pub(crate) async fn load_cli_auth_mode(config: &Config) -> Option<AuthMode> {
config.cli_auth_credentials_store_mode,
Some(&config.chatgpt_base_url),
config.auth_keyring_backend_kind(),
Some(&auth_route_config),
&auth_route_config,
)
.await
.ok()
+1 -1
View File
@@ -113,7 +113,7 @@ async fn auth_manager_with_agent_identity_business_plan() -> Arc<AuthManager> {
task_id: Some("task-123".to_string()),
},
"https://auth.openai.com/api/accounts",
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await
.expect("agent identity record should be complete"),
+1 -1
View File
@@ -1715,7 +1715,7 @@ async fn prefers_apikey_when_config_prefers_apikey_even_with_chatgpt_tokens() {
AuthCredentialsStoreMode::File,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await
.expect("Failed to load CodexAuth")
+1 -1
View File
@@ -589,7 +589,7 @@ async fn remote_compact_uses_agent_identity_assertion() -> Result<()> {
task_id: Some("task-compact".to_string()),
},
"https://auth.openai.com/api/accounts",
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await?,
)),
+2
View File
@@ -36,6 +36,8 @@ pub use crate::outbound_proxy::HttpClientFactory;
pub use crate::outbound_proxy::OutboundProxyPolicy;
pub use crate::outbound_proxy::OutboundProxyRoute;
pub use crate::outbound_proxy::RouteFailureClass;
#[doc(hidden)]
pub use crate::outbound_proxy::cache_system_proxy_route_for_test;
pub use crate::request::EncodedJsonBody;
pub use crate::request::PreparedRequestBody;
pub use crate::request::Request;
+8 -1
View File
@@ -544,7 +544,6 @@ fn cached_system_proxy_decision_from_cache(
None
}
#[cfg(test)]
fn cache_system_proxy_decision(request_url: &str, decision: SystemProxyDecision) {
let cache = SYSTEM_PROXY_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
if let Ok(mut cache) = cache.lock() {
@@ -553,6 +552,14 @@ fn cache_system_proxy_decision(request_url: &str, decision: SystemProxyDecision)
}
}
/// Primes one proxy decision for cross-crate integration tests.
///
/// This is public only so tests in HTTP-client consumers can exercise system-proxy routing
/// deterministically on every supported platform.
pub fn cache_system_proxy_route_for_test(request_url: &str, proxy_url: String) {
cache_system_proxy_decision(request_url, SystemProxyDecision::Proxy { url: proxy_url });
}
fn insert_system_proxy_cache_entry(
cache: &mut HashMap<String, CachedSystemProxyDecision>,
cache_key: &str,
+8 -8
View File
@@ -102,7 +102,7 @@ impl AgentIdentityAuth {
pub async fn from_record(
mut record: AgentIdentityAuthRecord,
agent_identity_authapi_base_url: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Self> {
public_key_ssh_from_private_key_pkcs8_base64(&record.agent_private_key)
.map_err(std::io::Error::other)?;
@@ -125,7 +125,7 @@ impl AgentIdentityAuth {
jwt: &str,
chatgpt_base_url: &str,
agent_identity_authapi_base_url: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Self> {
let record = verified_record_from_jwt(jwt, chatgpt_base_url, auth_route_config).await?;
Self::from_record(record, agent_identity_authapi_base_url, auth_route_config).await
@@ -175,7 +175,7 @@ pub(super) async fn register_managed_chatgpt_agent_identity(
binding: ManagedChatGptAgentIdentityBinding,
agent_identity_authapi_base_url: &str,
session_source: SessionSource,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<AgentIdentityAuth> {
let key_material = generate_agent_key_material().map_err(std::io::Error::other)?;
let registration_url = agent_registration_url(agent_identity_authapi_base_url);
@@ -222,7 +222,7 @@ pub(super) async fn register_managed_chatgpt_agent_identity(
pub(super) async fn verified_record_from_jwt(
jwt: &str,
chatgpt_base_url: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<AgentIdentityAuthRecord> {
AgentIdentityAuthRecord::from_agent_identity_jwt(jwt)?;
let jwks_url = agent_identity_jwks_url(chatgpt_base_url);
@@ -302,7 +302,7 @@ where
async fn register_task_for_record_with_retries(
record: &AgentIdentityAuthRecord,
agent_identity_authapi_base_url: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<String> {
let task_registration_url =
agent_task_registration_url(agent_identity_authapi_base_url, &record.agent_runtime_id);
@@ -392,7 +392,7 @@ mod tests {
let auth = AgentIdentityAuth::from_record(
agent_identity_record_with_generated_key(),
&server.uri(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?;
@@ -437,7 +437,7 @@ mod tests {
&jwt,
&format!("{}/backend-api", server.uri()),
&server.uri(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?;
@@ -480,7 +480,7 @@ mod tests {
let auth = AgentIdentityAuth::from_record(
agent_identity_record_with_generated_key(),
&server.uri(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?;
+38 -38
View File
@@ -122,7 +122,7 @@ async fn login_with_access_token_writes_agent_identity_jwt() {
/*forced_chatgpt_workspace_id*/ None,
Some(&chatgpt_base_url),
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("login_with_access_token should succeed");
@@ -182,7 +182,7 @@ async fn stored_agent_identity_jwt_keeps_auth_json_unchanged() -> anyhow::Result
Some(&chatgpt_base_url),
AuthKeyringBackendKind::Direct,
Some(&authapi_base_url),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?
.expect("auth should load");
@@ -228,7 +228,7 @@ async fn login_with_access_token_writes_only_personal_access_token() {
Some(&allowed_workspaces),
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("personal access token login should succeed");
@@ -281,7 +281,7 @@ async fn login_with_access_token_rejects_personal_access_token_workspace_mismatc
Some(&allowed_workspaces),
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect_err("personal access token workspace mismatch should fail");
@@ -314,7 +314,7 @@ async fn login_with_access_token_rejects_invalid_personal_access_token() {
/*forced_chatgpt_workspace_id*/ None,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect_err("invalid personal access token should fail");
@@ -338,7 +338,7 @@ async fn login_with_access_token_rejects_invalid_jwt() {
/*forced_chatgpt_workspace_id*/ None,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect_err("invalid access token should fail");
@@ -370,7 +370,7 @@ async fn chatgpt_auth_registers_agent_identity_when_enabled() -> anyhow::Result<
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?
.expect("auth should load");
@@ -380,7 +380,7 @@ async fn chatgpt_auth_registers_agent_identity_when_enabled() -> anyhow::Result<
AgentIdentityAuthPolicy::JwtOnly,
/*agent_identity_authapi_base_url*/ None,
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await?
@@ -411,7 +411,7 @@ async fn chatgpt_auth_registers_agent_identity_when_enabled() -> anyhow::Result<
AgentIdentityAuthPolicy::ChatGptAuth,
Some(&server.uri()),
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await?
@@ -421,7 +421,7 @@ async fn chatgpt_auth_registers_agent_identity_when_enabled() -> anyhow::Result<
AgentIdentityAuthPolicy::ChatGptAuth,
Some(&server.uri()),
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await?
@@ -452,7 +452,7 @@ async fn chatgpt_auth_registers_agent_identity_when_enabled() -> anyhow::Result<
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?
.expect("auth should reload");
@@ -461,7 +461,7 @@ async fn chatgpt_auth_registers_agent_identity_when_enabled() -> anyhow::Result<
AgentIdentityAuthPolicy::ChatGptAuth,
Some(&server.uri()),
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await?
@@ -494,7 +494,7 @@ async fn chatgpt_auth_retries_transient_agent_identity_registration() -> anyhow:
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?
.expect("auth should load");
@@ -523,7 +523,7 @@ async fn chatgpt_auth_retries_transient_agent_identity_registration() -> anyhow:
AgentIdentityAuthPolicy::ChatGptAuth,
Some(&server.uri()),
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await?
@@ -560,7 +560,7 @@ async fn chatgpt_auth_registration_retry_exhaustion_is_fallback_eligible() -> an
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?
.expect("auth should load");
@@ -578,7 +578,7 @@ async fn chatgpt_auth_registration_retry_exhaustion_is_fallback_eligible() -> an
AgentIdentityAuthPolicy::ChatGptAuth,
Some(&server.uri()),
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await
@@ -621,7 +621,7 @@ async fn chatgpt_auth_task_registration_retry_exhaustion_is_fallback_eligible()
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?
.expect("auth should load");
@@ -642,7 +642,7 @@ async fn chatgpt_auth_task_registration_retry_exhaustion_is_fallback_eligible()
AgentIdentityAuthPolicy::ChatGptAuth,
Some(&server.uri()),
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await
@@ -677,7 +677,7 @@ async fn chatgpt_auth_non_retryable_registration_error_is_hard_failure() -> anyh
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await?
.expect("auth should load");
@@ -695,7 +695,7 @@ async fn chatgpt_auth_non_retryable_registration_error_is_hard_failure() -> anyh
AgentIdentityAuthPolicy::ChatGptAuth,
Some(&server.uri()),
/*forced_chatgpt_workspace_id*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
SessionSource::Cli,
)
.await
@@ -737,7 +737,7 @@ async fn agent_identity_jwt_task_registration_retry_exhaustion_is_strict() -> an
&agent_identity,
Some(&chatgpt_base_url),
&authapi_base_url,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect_err("agent identity jwt task retry exhaustion should fail");
@@ -768,7 +768,7 @@ async fn login_with_access_token_rejects_unsigned_jwt() {
/*forced_chatgpt_workspace_id*/ None,
Some(&chatgpt_base_url),
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect_err("unsigned access token should fail");
@@ -790,7 +790,7 @@ async fn missing_auth_json_returns_none() {
AuthCredentialsStoreMode::File,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("call should succeed");
@@ -820,7 +820,7 @@ async fn pro_account_with_no_api_key_uses_chatgpt_auth() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.unwrap()
@@ -882,7 +882,7 @@ async fn loads_api_key_from_auth_json() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.unwrap()
@@ -978,7 +978,7 @@ async fn refresh_failure_is_scoped_to_the_matching_auth_snapshot() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("load auth")
@@ -999,7 +999,7 @@ async fn refresh_failure_is_scoped_to_the_matching_auth_snapshot() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("updated auth should parse");
@@ -1427,7 +1427,7 @@ async fn load_auth_reads_access_token_from_env() {
Some(&chatgpt_base_url),
AuthKeyringBackendKind::Direct,
Some(&authapi_base_url),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("env auth should load")
@@ -1475,7 +1475,7 @@ async fn load_auth_reads_personal_access_token_from_env() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("env auth should load")
@@ -1569,7 +1569,7 @@ async fn auth_manager_rejects_stored_personal_access_token_workspace_mismatch()
/*forced_chatgpt_workspace_id*/ None,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("personal access token login should succeed");
@@ -1648,7 +1648,7 @@ async fn load_auth_keeps_codex_api_key_env_precedence() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("env auth should load")
@@ -1745,7 +1745,7 @@ async fn enforce_login_restrictions_logs_out_for_personal_access_token_workspace
/*forced_chatgpt_workspace_id*/ None,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("personal access token login should succeed");
@@ -2134,7 +2134,7 @@ async fn assert_agent_identity_plan_alias(
&jwt,
Some(&chatgpt_base_url),
&authapi_base_url,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("agent identity auth");
@@ -2166,7 +2166,7 @@ async fn plan_type_maps_known_plan() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("load auth")
@@ -2198,7 +2198,7 @@ async fn plan_type_maps_self_serve_business_usage_based_plan() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("load auth")
@@ -2233,7 +2233,7 @@ async fn plan_type_maps_enterprise_cbp_usage_based_plan() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("load auth")
@@ -2268,7 +2268,7 @@ async fn plan_type_maps_unknown_to_unknown() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("load auth")
@@ -2300,7 +2300,7 @@ async fn missing_plan_type_maps_to_unknown() {
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::Direct,
/*agent_identity_authapi_base_url*/ None,
/*auth_route_config*/ None,
&crate::test_support::transport_default_auth_route_config(),
)
.await
.expect("load auth")
+5 -11
View File
@@ -299,31 +299,25 @@ fn build_default_client(builder: HttpClientBuilder) -> HttpClient {
/// Builds an HTTP client for an auth endpoint without Codex default headers.
pub(crate) fn create_raw_auth_client(
endpoint: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> Result<HttpClient, BuildRouteAwareHttpClientError> {
auth_http_client_factory(auth_route_config)
auth_route_config
.http_client_factory()
.build_client_without_request_logging(endpoint, ClientRouteClass::Auth)
}
/// Builds the default Codex HTTP client wrapper for an auth endpoint.
pub(crate) fn create_default_auth_client(
endpoint: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> Result<HttpClient, BuildRouteAwareHttpClientError> {
create_client_for_route(
&auth_http_client_factory(auth_route_config),
auth_route_config.http_client_factory(),
endpoint,
ClientRouteClass::Auth,
)
}
fn auth_http_client_factory(auth_route_config: Option<&AuthRouteConfig>) -> HttpClientFactory {
auth_route_config.map_or_else(
|| HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault),
|config| config.http_client_factory().clone(),
)
}
pub fn default_headers() -> HeaderMap {
let mut headers = HeaderMap::new();
headers.insert("originator", originator().header_value);
@@ -198,8 +198,11 @@ async fn raw_auth_client_does_not_log_sensitive_request_or_response_data() {
let endpoint = format!(
"http://auth-user:password-secret-value@{authority}/token?client_secret=query-secret-value"
);
let client = create_raw_auth_client(&endpoint, /*auth_route_config*/ None)
.expect("raw auth client should build");
let client = create_raw_auth_client(
&endpoint,
&crate::test_support::transport_default_auth_route_config(),
)
.expect("raw auth client should build");
let buffer = Arc::new(Mutex::new(Vec::new()));
let subscriber = tracing_subscriber::registry().with(
tracing_subscriber::fmt::layer()
@@ -228,9 +231,11 @@ async fn raw_auth_client_does_not_log_sensitive_request_or_response_data() {
let unresponsive_endpoint = format!(
"http://auth-user:failure-password-secret-value@{unresponsive_addr}/token?client_secret=failure-query-secret-value"
);
let unresponsive_client =
create_raw_auth_client(&unresponsive_endpoint, /*auth_route_config*/ None)
.expect("raw auth client should build");
let unresponsive_client = create_raw_auth_client(
&unresponsive_endpoint,
&crate::test_support::transport_default_auth_route_config(),
)
.expect("raw auth client should build");
let error = unresponsive_client
.post(&unresponsive_endpoint)
.header("x-sensitive-request", "failure-request-header-secret-value")
+16 -17
View File
@@ -253,7 +253,7 @@ impl CodexAuth {
chatgpt_base_url: Option<&str>,
keyring_backend_kind: AuthKeyringBackendKind,
agent_identity_authapi_base_url: Option<&str>,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Self> {
let auth_mode = auth_dot_json.resolved_mode();
if auth_mode == AuthMode::ApiKey {
@@ -353,7 +353,7 @@ impl CodexAuth {
auth_credentials_store_mode: AuthCredentialsStoreMode,
chatgpt_base_url: Option<&str>,
keyring_backend_kind: AuthKeyringBackendKind,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Option<Self>> {
let agent_identity_authapi_base_url =
agent_identity_authapi_base_url(chatgpt_base_url).ok();
@@ -373,7 +373,7 @@ impl CodexAuth {
pub async fn from_agent_identity_jwt(
jwt: &str,
chatgpt_base_url: Option<&str>,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Self> {
let agent_identity_authapi_base_url = agent_identity_authapi_base_url(chatgpt_base_url)?;
Self::from_agent_identity_jwt_with_authapi_base_url(
@@ -389,7 +389,7 @@ impl CodexAuth {
jwt: &str,
chatgpt_base_url: Option<&str>,
agent_identity_authapi_base_url: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Self> {
let base_url = chatgpt_base_url
.unwrap_or(ChatGptEnvironment::default().chatgpt_base_url())
@@ -408,7 +408,7 @@ impl CodexAuth {
pub async fn from_personal_access_token(
access_token: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Self> {
Ok(Self::PersonalAccessToken(
PersonalAccessTokenAuth::load(access_token, auth_route_config).await?,
@@ -632,7 +632,7 @@ impl CodexAuth {
policy: AgentIdentityAuthPolicy,
agent_identity_authapi_base_url: Option<&str>,
forced_chatgpt_workspace_id: Option<Vec<String>>,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
session_source: SessionSource,
) -> std::io::Result<Option<AgentIdentityAuth>> {
match self {
@@ -662,7 +662,7 @@ impl CodexAuth {
&self,
agent_identity_authapi_base_url: &str,
forced_chatgpt_workspace_id: Option<Vec<String>>,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
session_source: SessionSource,
) -> std::io::Result<AgentIdentityAuth> {
let binding =
@@ -880,7 +880,7 @@ pub async fn logout_with_revoke(
codex_home: &Path,
auth_credentials_store_mode: AuthCredentialsStoreMode,
keyring_backend_kind: AuthKeyringBackendKind,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<bool> {
let auth_dot_json = match load_auth_dot_json(
codex_home,
@@ -935,7 +935,7 @@ pub async fn login_with_access_token(
forced_chatgpt_workspace_id: Option<&[String]>,
chatgpt_base_url: Option<&str>,
keyring_backend_kind: AuthKeyringBackendKind,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<()> {
let auth_dot_json = match classify_codex_access_token(access_token) {
CodexAccessToken::PersonalAccessToken(access_token) => {
@@ -1073,7 +1073,7 @@ async fn enforce_login_restrictions_with_agent_identity_authapi_base_url(
config.chatgpt_base_url.as_deref(),
config.keyring_backend_kind,
agent_identity_authapi_base_url,
Some(&config.auth_route_config),
&config.auth_route_config,
)
.await?
else {
@@ -1222,7 +1222,7 @@ async fn load_auth(
chatgpt_base_url: Option<&str>,
keyring_backend_kind: AuthKeyringBackendKind,
agent_identity_authapi_base_url: Option<&str>,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Option<CodexAuth>> {
// API key via env var takes precedence over any other auth method.
if enable_codex_api_key_env && let Some(api_key) = read_codex_api_key_from_env() {
@@ -1859,7 +1859,7 @@ impl AuthManager {
chatgpt_base_url.as_deref(),
keyring_backend_kind,
agent_identity_authapi_base_url.as_deref(),
Some(&auth_route_config),
&auth_route_config,
)
.await
.ok()
@@ -2080,7 +2080,7 @@ impl AuthManager {
policy,
self.agent_identity_authapi_base_url.as_deref(),
forced_chatgpt_workspace_id,
Some(&self.auth_route_config),
&self.auth_route_config,
session_source,
)
.await;
@@ -2099,7 +2099,7 @@ impl AuthManager {
policy,
self.agent_identity_authapi_base_url.as_deref(),
self.forced_chatgpt_workspace_id(),
Some(&self.auth_route_config),
&self.auth_route_config,
session_source,
)
.await
@@ -2218,7 +2218,7 @@ impl AuthManager {
self.chatgpt_base_url.as_deref(),
self.keyring_backend_kind,
self.agent_identity_authapi_base_url.as_deref(),
Some(&self.auth_route_config),
&self.auth_route_config,
)
.await
.ok()
@@ -2478,8 +2478,7 @@ impl AuthManager {
let auth_dot_json = self
.auth_cached()
.and_then(|auth| auth.get_current_auth_json());
if let Err(err) =
revoke_auth_tokens(auth_dot_json.as_ref(), Some(&self.auth_route_config)).await
if let Err(err) = revoke_auth_tokens(auth_dot_json.as_ref(), &self.auth_route_config).await
{
tracing::warn!("failed to revoke auth tokens during logout: {err}");
}
@@ -39,7 +39,7 @@ impl fmt::Debug for PersonalAccessTokenAuth {
impl PersonalAccessTokenAuth {
pub(super) async fn load(
access_token: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> std::io::Result<Self> {
let authapi_base_url = env::var(CODEX_AUTHAPI_BASE_URL_ENV_VAR)
.ok()
+1 -1
View File
@@ -54,7 +54,7 @@ struct RevokeTokenRequest<'a> {
pub(super) async fn revoke_auth_tokens(
auth_dot_json: Option<&AuthDotJson>,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> Result<(), std::io::Error> {
let Some((token, kind)) = auth_dot_json.and_then(revocable_token) else {
return Ok(());
+3 -3
View File
@@ -166,7 +166,7 @@ pub async fn request_device_code(opts: &ServerOptions) -> std::io::Result<Device
let base_url = opts.issuer.trim_end_matches('/');
// The route selected for the issuer is reused for all device-auth endpoint paths; the endpoint
// paths are not resolved separately.
let client = create_raw_auth_client(base_url, opts.auth_route_config.as_ref())?;
let client = create_raw_auth_client(base_url, &opts.auth_route_config)?;
let api_base_url = format!("{base_url}/api/accounts");
let uc = request_user_code(&client, &api_base_url, &opts.client_id).await?;
@@ -183,7 +183,7 @@ pub async fn complete_device_code_login(
device_code: DeviceCode,
) -> std::io::Result<()> {
let base_url = opts.issuer.trim_end_matches('/');
let client = create_raw_auth_client(base_url, opts.auth_route_config.as_ref())?;
let client = create_raw_auth_client(base_url, &opts.auth_route_config)?;
let api_base_url = format!("{base_url}/api/accounts");
let code_resp = poll_for_token(
@@ -207,7 +207,7 @@ pub async fn complete_device_code_login(
&redirect_uri,
&pkce,
&code_resp.authorization_code,
opts.auth_route_config.as_ref(),
&opts.auth_route_config,
)
.await
.map_err(|err| std::io::Error::other(format!("device code exchange failed: {err}")))?;
+6 -6
View File
@@ -77,7 +77,7 @@ pub struct ServerOptions {
pub login_success_page: LoginSuccessPage,
pub cli_auth_credentials_store_mode: AuthCredentialsStoreMode,
pub auth_keyring_backend_kind: AuthKeyringBackendKind,
pub auth_route_config: Option<AuthRouteConfig>,
pub auth_route_config: AuthRouteConfig,
}
impl ServerOptions {
@@ -88,7 +88,7 @@ impl ServerOptions {
forced_chatgpt_workspace_id: Option<Vec<String>>,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode,
auth_keyring_backend_kind: AuthKeyringBackendKind,
auth_route_config: Option<AuthRouteConfig>,
auth_route_config: AuthRouteConfig,
) -> Self {
Self {
codex_home,
@@ -387,7 +387,7 @@ async fn process_request(
redirect_uri,
pkce,
&code,
opts.auth_route_config.as_ref(),
&opts.auth_route_config,
)
.await
{
@@ -409,7 +409,7 @@ async fn process_request(
&opts.issuer,
&opts.client_id,
&tokens.id_token,
opts.auth_route_config.as_ref(),
&opts.auth_route_config,
)
.await
.ok();
@@ -789,7 +789,7 @@ pub(crate) async fn exchange_code_for_tokens(
redirect_uri: &str,
pkce: &PkceCodes,
code: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> io::Result<ExchangedTokens> {
#[derive(serde::Deserialize)]
struct TokenResponse {
@@ -1114,7 +1114,7 @@ pub(crate) async fn obtain_api_key(
issuer: &str,
client_id: &str,
id_token: &str,
auth_route_config: Option<&AuthRouteConfig>,
auth_route_config: &AuthRouteConfig,
) -> io::Result<String> {
// Token exchange for an API key access token
#[derive(serde::Deserialize)]
+147
View File
@@ -4,6 +4,9 @@ use base64::Engine;
use chrono::Duration;
use chrono::Utc;
use codex_config::types::AuthCredentialsStoreMode;
use codex_http_client::HttpClientFactory;
use codex_http_client::OutboundProxyPolicy;
use codex_http_client::cache_system_proxy_route_for_test;
use codex_login::AuthDotJson;
use codex_login::AuthKeyringBackendKind;
use codex_login::AuthManager;
@@ -21,7 +24,10 @@ use pretty_assertions::assert_eq;
use serde::Serialize;
use serde_json::json;
use std::ffi::OsString;
use std::net::TcpListener;
use std::process::Command;
use std::sync::Arc;
use std::time::Duration as StdDuration;
use tempfile::TempDir;
use wiremock::Mock;
use wiremock::MockServer;
@@ -31,6 +37,147 @@ use wiremock::matchers::path;
const INITIAL_ACCESS_TOKEN: &str = "initial-access-token";
const INITIAL_REFRESH_TOKEN: &str = "initial-refresh-token";
const SYSTEM_PROXY_TEST_ENDPOINT: &str = "http://auth-proxy.invalid/oauth/token";
const SYSTEM_PROXY_TEST_SUBPROCESS_ENV_VAR: &str = "CODEX_AUTH_SYSTEM_PROXY_TEST_SUBPROCESS";
const SYSTEM_PROXY_TEST_PROXY_URL_ENV_VAR: &str = "CODEX_AUTH_SYSTEM_PROXY_TEST_PROXY_URL";
const SYSTEM_PROXY_TEST_NAME: &str =
"suite::auth_refresh::refresh_token_honors_respect_system_proxy";
const PROXY_ENV_KEYS: [&str; 8] = [
"HTTP_PROXY",
"http_proxy",
"HTTPS_PROXY",
"https_proxy",
"ALL_PROXY",
"all_proxy",
"NO_PROXY",
"no_proxy",
];
#[serial_test::serial(auth_env)]
#[tokio::test]
async fn refresh_token_honors_respect_system_proxy() -> Result<()> {
skip_if_no_network!(Ok(()));
if std::env::var_os(SYSTEM_PROXY_TEST_SUBPROCESS_ENV_VAR).is_none() {
let response_body =
r#"{"access_token":"new-access-token","refresh_token":"new-refresh-token"}"#;
let listener = TcpListener::bind(("127.0.0.1", 0))?;
let proxy_address = listener.local_addr()?;
let proxy = tiny_http::Server::from_listener(listener, None)
.map_err(|error| anyhow::anyhow!("failed to start auth proxy: {error}"))?;
let proxy_thread = std::thread::spawn(move || {
let mut request = proxy
.recv_timeout(StdDuration::from_secs(30))
.expect("proxy should receive an auth refresh request")
.expect("proxy should receive a request before the timeout");
let request_line = format!("{} {} HTTP/1.1", request.method(), request.url());
let mut request_body = String::new();
request
.as_reader()
.read_to_string(&mut request_body)
.expect("proxy should read request body");
let content_type = tiny_http::Header::from_bytes(
b"Content-Type".as_slice(),
b"application/json".as_slice(),
)
.expect("content type header should be valid");
request
.respond(tiny_http::Response::from_string(response_body).with_header(content_type))
.expect("proxy should write response");
(request_line, request_body)
});
let proxy_url = format!("http://{proxy_address}");
let mut command = Command::new(std::env::current_exe()?);
command.arg("--exact").arg(SYSTEM_PROXY_TEST_NAME);
for key in PROXY_ENV_KEYS {
command.env_remove(key);
}
command
.env(SYSTEM_PROXY_TEST_SUBPROCESS_ENV_VAR, "1")
.env(SYSTEM_PROXY_TEST_PROXY_URL_ENV_VAR, proxy_url)
.env(CLIENT_ID_OVERRIDE_ENV_VAR, "staging-client")
.env_remove(REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR);
let output = command.output()?;
assert!(
output.status.success(),
"subprocess test `{SYSTEM_PROXY_TEST_NAME}` failed\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
let (proxy_request_line, proxy_request_body) = proxy_thread
.join()
.expect("proxy thread should finish after the child test");
assert_eq!(
proxy_request_line,
"POST http://auth-proxy.invalid/oauth/token HTTP/1.1"
);
assert_eq!(
serde_json::from_str::<serde_json::Value>(&proxy_request_body)?,
json!({
"client_id": "staging-client",
"grant_type": "refresh_token",
"refresh_token": INITIAL_REFRESH_TOKEN,
})
);
return Ok(());
}
let codex_home = TempDir::new()?;
let proxy_url = std::env::var(SYSTEM_PROXY_TEST_PROXY_URL_ENV_VAR)
.context("proxy URL should be set in the auth refresh test subprocess")?;
cache_system_proxy_route_for_test(SYSTEM_PROXY_TEST_ENDPOINT, proxy_url);
let _endpoint_guard = EnvGuard::set(
REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR,
SYSTEM_PROXY_TEST_ENDPOINT.to_string(),
);
let auth_manager = AuthManager::shared(
codex_home.path().to_path_buf(),
/*enable_codex_api_key_env*/ false,
AuthCredentialsStoreMode::File,
/*forced_chatgpt_workspace_id*/ None,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/
codex_login::AuthRouteConfig::from_http_client_factory(HttpClientFactory::new(
OutboundProxyPolicy::RespectSystemProxy,
)),
)
.await;
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
let initial_auth = AuthDotJson {
auth_mode: Some(AuthMode::Chatgpt),
openai_api_key: None,
tokens: Some(initial_tokens.clone()),
last_refresh: Some(Utc::now() - Duration::days(1)),
agent_identity: None,
personal_access_token: None,
bedrock_api_key: None,
};
save_auth(
codex_home.path(),
&initial_auth,
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
)?;
auth_manager.reload().await;
auth_manager
.refresh_token_from_authority()
.await
.context("refresh should succeed through the configured proxy")?;
let refreshed_auth = auth_manager.auth().await.context("auth should be cached")?;
let expected_tokens = TokenData {
access_token: "new-access-token".to_string(),
refresh_token: "new-refresh-token".to_string(),
..initial_tokens
};
assert_eq!(refreshed_auth.get_token_data()?, expected_tokens);
Ok(())
}
#[serial_test::serial(auth_env)]
#[tokio::test]
@@ -112,7 +112,7 @@ fn server_opts(
/*forced_chatgpt_workspace_id*/ None,
cli_auth_credentials_store_mode,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
codex_login::test_support::transport_default_auth_route_config(),
);
opts.issuer = issuer;
opts.open_browser = false;
@@ -278,7 +278,7 @@ async fn device_code_login_integration_persists_without_api_key_on_exchange_fail
/*forced_chatgpt_workspace_id*/ None,
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
codex_login::test_support::transport_default_auth_route_config(),
);
opts.issuer = issuer;
opts.open_browser = false;
@@ -334,7 +334,7 @@ async fn device_code_login_integration_handles_error_payload() -> anyhow::Result
/*forced_chatgpt_workspace_id*/ None,
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
codex_login::test_support::transport_default_auth_route_config(),
);
opts.issuer = issuer;
opts.open_browser = false;
+10 -10
View File
@@ -125,7 +125,7 @@ async fn end_to_end_login_flow_persists_auth_json() -> Result<()> {
let opts = ServerOptions {
codex_home: server_home,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: 0,
@@ -190,7 +190,7 @@ async fn hosted_login_redirects_to_configured_open_app_url() -> Result<()> {
let server = run_login_server(ServerOptions {
codex_home: tmp.path().to_path_buf(),
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: 0,
@@ -243,7 +243,7 @@ async fn creates_missing_codex_home_dir() -> Result<()> {
let opts = ServerOptions {
codex_home: server_home,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: 0,
@@ -286,7 +286,7 @@ async fn login_server_includes_forced_workspaces_as_one_query_param() -> Result<
let opts = ServerOptions {
codex_home,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: 0,
@@ -330,7 +330,7 @@ async fn forced_chatgpt_workspace_id_mismatch_blocks_login() -> Result<()> {
let opts = ServerOptions {
codex_home: codex_home.clone(),
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: 0,
@@ -393,7 +393,7 @@ async fn oauth_access_denied_missing_entitlement_blocks_login_with_clear_error()
let opts = ServerOptions {
codex_home: codex_home.clone(),
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: 0,
@@ -464,7 +464,7 @@ async fn oauth_access_denied_unknown_reason_uses_generic_error_page() -> Result<
let opts = ServerOptions {
codex_home: codex_home.clone(),
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: 0,
@@ -575,7 +575,7 @@ async fn falls_back_to_registered_fallback_port_when_default_port_is_in_use() ->
/*forced_chatgpt_workspace_id*/ None,
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
codex_login::test_support::transport_default_auth_route_config(),
);
opts.issuer = issuer;
opts.open_browser = false;
@@ -614,7 +614,7 @@ async fn cancels_previous_login_server_when_port_is_in_use() -> Result<()> {
let first_opts = ServerOptions {
codex_home: first_codex_home,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer: issuer.clone(),
port: 0,
@@ -638,7 +638,7 @@ async fn cancels_previous_login_server_when_port_is_in_use() -> Result<()> {
let second_opts = ServerOptions {
codex_home: second_codex_home,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
auth_route_config: None,
auth_route_config: codex_login::test_support::transport_default_auth_route_config(),
client_id: codex_login::CLIENT_ID.to_string(),
issuer,
port: login_port,
+3 -3
View File
@@ -61,7 +61,7 @@ async fn logout_with_revoke_revokes_refresh_token_then_removes_auth() -> Result<
codex_home.path(),
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await?;
@@ -120,7 +120,7 @@ async fn logout_with_revoke_uses_stored_auth_when_access_token_env_is_set() -> R
codex_home.path(),
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await?;
@@ -163,7 +163,7 @@ async fn logout_with_revoke_removes_auth_when_revoke_fails() -> Result<()> {
codex_home.path(),
AuthCredentialsStoreMode::File,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await?;
+1 -1
View File
@@ -355,7 +355,7 @@ mod tests {
task_id: Some("task-run-1".to_string()),
},
"https://auth.openai.com/api/accounts",
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await
.expect("agent identity auth record should include task id")
+1 -1
View File
@@ -271,7 +271,7 @@ c2ln",
AuthCredentialsStoreMode::File,
/*chatgpt_base_url*/ None,
AuthKeyringBackendKind::default(),
/*auth_route_config*/ None,
&codex_login::test_support::transport_default_auth_route_config(),
)
.await
.expect("auth should load")