mirror of
https://github.com/openai/codex.git
synced 2026-09-13 11:47:17 +00:00
login: use route-aware HTTP client abstraction
This commit is contained in:
1
codex-rs/Cargo.lock
generated
1
codex-rs/Cargo.lock
generated
@@ -3350,6 +3350,7 @@ dependencies = [
|
||||
"codex-terminal-detection",
|
||||
"codex-utils-template",
|
||||
"core_test_support",
|
||||
"http 1.4.0",
|
||||
"jsonwebtoken",
|
||||
"keyring",
|
||||
"once_cell",
|
||||
|
||||
@@ -15,6 +15,7 @@ use std::time::Instant;
|
||||
|
||||
use crate::custom_ca::BuildCustomCaTransportError;
|
||||
use crate::custom_ca::build_reqwest_client_with_custom_ca;
|
||||
use crate::default_client::HttpClient;
|
||||
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
||||
use sha2::Digest;
|
||||
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
||||
@@ -158,6 +159,16 @@ impl HttpClientFactory {
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds an HTTP client for a concrete outbound route.
|
||||
pub fn build_client(
|
||||
&self,
|
||||
request_url: &str,
|
||||
route_class: ClientRouteClass,
|
||||
) -> Result<HttpClient, BuildRouteAwareHttpClientError> {
|
||||
self.build_reqwest_client(reqwest::Client::builder(), request_url, route_class)
|
||||
.map(HttpClient::new)
|
||||
}
|
||||
|
||||
/// Builds a reqwest client for a concrete outbound route.
|
||||
pub fn build_reqwest_client(
|
||||
&self,
|
||||
|
||||
@@ -20,6 +20,7 @@ codex-protocol = { workspace = true }
|
||||
codex-secrets = { workspace = true }
|
||||
codex-terminal-detection = { workspace = true }
|
||||
codex-utils-template = { workspace = true }
|
||||
http = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
os_info = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
|
||||
@@ -295,16 +295,12 @@ fn default_reqwest_client_builder() -> reqwest::ClientBuilder {
|
||||
with_chatgpt_cloudflare_cookie_store(builder)
|
||||
}
|
||||
|
||||
/// Builds a raw reqwest client for an auth endpoint without Codex default headers.
|
||||
pub(crate) fn build_raw_auth_reqwest_client(
|
||||
/// 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>,
|
||||
) -> Result<reqwest::Client, BuildRouteAwareHttpClientError> {
|
||||
auth_http_client_factory(auth_route_config).build_reqwest_client(
|
||||
reqwest::Client::builder(),
|
||||
endpoint,
|
||||
ClientRouteClass::Auth,
|
||||
)
|
||||
) -> Result<HttpClient, BuildRouteAwareHttpClientError> {
|
||||
auth_http_client_factory(auth_route_config).build_client(endpoint, ClientRouteClass::Auth)
|
||||
}
|
||||
|
||||
/// Builds the default Codex reqwest client for an auth endpoint.
|
||||
|
||||
@@ -155,6 +155,9 @@ fn derive_revoke_token_endpoint(refresh_endpoint: &str) -> Option<String> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codex_http_client::ClientRouteClass;
|
||||
use codex_http_client::HttpClientFactory;
|
||||
use codex_http_client::OutboundProxyPolicy;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use wiremock::Mock;
|
||||
use wiremock::MockServer;
|
||||
@@ -181,8 +184,10 @@ mod tests {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let client = HttpClient::new(reqwest::Client::new());
|
||||
let endpoint = format!("{}/oauth/revoke", server.uri());
|
||||
let client = HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault)
|
||||
.build_client(&endpoint, ClientRouteClass::Auth)
|
||||
.expect("test HTTP client should build");
|
||||
let error = revoke_oauth_token(
|
||||
&client,
|
||||
endpoint.as_str(),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use reqwest::StatusCode;
|
||||
use codex_http_client::HttpClient;
|
||||
use http::StatusCode;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde::de::Deserializer;
|
||||
@@ -6,7 +7,7 @@ use serde::de::{self};
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::default_client::build_raw_auth_reqwest_client;
|
||||
use crate::default_client::create_raw_auth_client;
|
||||
use crate::pkce::PkceCodes;
|
||||
use crate::server::ServerOptions;
|
||||
use std::io;
|
||||
@@ -60,7 +61,7 @@ struct CodeSuccessResp {
|
||||
|
||||
/// Request the user code and polling interval.
|
||||
async fn request_user_code(
|
||||
client: &reqwest::Client,
|
||||
client: &HttpClient,
|
||||
auth_base_url: &str,
|
||||
client_id: &str,
|
||||
) -> std::io::Result<UserCodeResp> {
|
||||
@@ -97,7 +98,7 @@ async fn request_user_code(
|
||||
|
||||
/// Poll token endpoint until a code is issued or timeout occurs.
|
||||
async fn poll_for_token(
|
||||
client: &reqwest::Client,
|
||||
client: &HttpClient,
|
||||
auth_base_url: &str,
|
||||
device_auth_id: &str,
|
||||
user_code: &str,
|
||||
@@ -165,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 = build_raw_auth_reqwest_client(base_url, opts.auth_route_config.as_ref())?;
|
||||
let client = create_raw_auth_client(base_url, opts.auth_route_config.as_ref())?;
|
||||
let api_base_url = format!("{base_url}/api/accounts");
|
||||
let uc = request_user_code(&client, &api_base_url, &opts.client_id).await?;
|
||||
|
||||
@@ -182,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 = build_raw_auth_reqwest_client(base_url, opts.auth_route_config.as_ref())?;
|
||||
let client = create_raw_auth_client(base_url, opts.auth_route_config.as_ref())?;
|
||||
let api_base_url = format!("{base_url}/api/accounts");
|
||||
|
||||
let code_resp = poll_for_token(
|
||||
|
||||
@@ -27,7 +27,7 @@ use std::time::Duration;
|
||||
use crate::auth::AuthDotJson;
|
||||
use crate::auth::AuthKeyringBackendKind;
|
||||
use crate::auth::save_auth;
|
||||
use crate::default_client::build_raw_auth_reqwest_client;
|
||||
use crate::default_client::create_raw_auth_client;
|
||||
use crate::default_client::originator;
|
||||
use crate::outbound_proxy::AuthRouteConfig;
|
||||
use crate::pkce::PkceCodes;
|
||||
@@ -798,7 +798,7 @@ pub(crate) async fn exchange_code_for_tokens(
|
||||
|
||||
// The route selected for the issuer is reused for token exchange; the token endpoint path is
|
||||
// not resolved separately.
|
||||
let client = build_raw_auth_reqwest_client(issuer.trim_end_matches('/'), auth_route_config)?;
|
||||
let client = create_raw_auth_client(issuer.trim_end_matches('/'), auth_route_config)?;
|
||||
let token_endpoint = format!("{}/oauth/token", issuer.trim_end_matches('/'));
|
||||
info!(
|
||||
issuer = %sanitize_url_for_logging(issuer),
|
||||
@@ -1120,7 +1120,7 @@ pub(crate) async fn obtain_api_key(
|
||||
access_token: String,
|
||||
}
|
||||
let token_endpoint = format!("{}/oauth/token", issuer.trim_end_matches('/'));
|
||||
let client = build_raw_auth_reqwest_client(&token_endpoint, auth_route_config)?;
|
||||
let client = create_raw_auth_client(&token_endpoint, auth_route_config)?;
|
||||
let resp = client
|
||||
.post(token_endpoint)
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
Reference in New Issue
Block a user