diff --git a/codex-rs/cli/src/login.rs b/codex-rs/cli/src/login.rs index b8a8e45e..cff03e7c 100644 --- a/codex-rs/cli/src/login.rs +++ b/codex-rs/cli/src/login.rs @@ -12,8 +12,8 @@ use codex_protocol::mcp_protocol::AuthMode; use std::env; use std::path::PathBuf; -pub async fn login_with_chatgpt(codex_home: PathBuf) -> std::io::Result<()> { - let opts = ServerOptions::new(codex_home, CLIENT_ID.to_string()); +pub async fn login_with_chatgpt(codex_home: PathBuf, originator: String) -> std::io::Result<()> { + let opts = ServerOptions::new(codex_home, CLIENT_ID.to_string(), originator); let server = run_login_server(opts)?; eprintln!( @@ -27,7 +27,12 @@ pub async fn login_with_chatgpt(codex_home: PathBuf) -> std::io::Result<()> { pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) -> ! { let config = load_config_or_exit(cli_config_overrides); - match login_with_chatgpt(config.codex_home).await { + match login_with_chatgpt( + config.codex_home, + config.responses_originator_header.clone(), + ) + .await + { Ok(_) => { eprintln!("Successfully logged in"); std::process::exit(0); diff --git a/codex-rs/login/src/server.rs b/codex-rs/login/src/server.rs index 5cc08d42..bca3b164 100644 --- a/codex-rs/login/src/server.rs +++ b/codex-rs/login/src/server.rs @@ -30,10 +30,11 @@ pub struct ServerOptions { pub port: u16, pub open_browser: bool, pub force_state: Option, + pub originator: String, } impl ServerOptions { - pub fn new(codex_home: PathBuf, client_id: String) -> Self { + pub fn new(codex_home: PathBuf, client_id: String, originator: String) -> Self { Self { codex_home, client_id: client_id.to_string(), @@ -41,6 +42,7 @@ impl ServerOptions { port: DEFAULT_PORT, open_browser: true, force_state: None, + originator, } } } @@ -96,7 +98,14 @@ pub fn run_login_server(opts: ServerOptions) -> io::Result { let server = Arc::new(server); let redirect_uri = format!("http://localhost:{actual_port}/auth/callback"); - let auth_url = build_authorize_url(&opts.issuer, &opts.client_id, &redirect_uri, &pkce, &state); + let auth_url = build_authorize_url( + &opts.issuer, + &opts.client_id, + &redirect_uri, + &pkce, + &state, + &opts.originator, + ); if opts.open_browser { let _ = webbrowser::open(&auth_url); @@ -279,6 +288,7 @@ fn build_authorize_url( redirect_uri: &str, pkce: &PkceCodes, state: &str, + originator: &str, ) -> String { let query = vec![ ("response_type", "code"), @@ -290,6 +300,7 @@ fn build_authorize_url( ("id_token_add_organizations", "true"), ("codex_cli_simplified_flow", "true"), ("state", state), + ("originator", originator), ]; let qs = query .into_iter() diff --git a/codex-rs/login/tests/suite/login_server_e2e.rs b/codex-rs/login/tests/suite/login_server_e2e.rs index ceb0a947..ef6b80fb 100644 --- a/codex-rs/login/tests/suite/login_server_e2e.rs +++ b/codex-rs/login/tests/suite/login_server_e2e.rs @@ -100,6 +100,7 @@ async fn end_to_end_login_flow_persists_auth_json() { port: 0, open_browser: false, force_state: Some(state), + originator: "test_originator".to_string(), }; let server = run_login_server(opts).unwrap(); let login_port = server.actual_port; @@ -158,6 +159,7 @@ async fn creates_missing_codex_home_dir() { port: 0, open_browser: false, force_state: Some(state), + originator: "test_originator".to_string(), }; let server = run_login_server(opts).unwrap(); let login_port = server.actual_port; diff --git a/codex-rs/mcp-server/src/codex_message_processor.rs b/codex-rs/mcp-server/src/codex_message_processor.rs index 72474d98..fd82496a 100644 --- a/codex-rs/mcp-server/src/codex_message_processor.rs +++ b/codex-rs/mcp-server/src/codex_message_processor.rs @@ -160,7 +160,11 @@ impl CodexMessageProcessor { let opts = LoginServerOptions { open_browser: false, - ..LoginServerOptions::new(config.codex_home.clone(), CLIENT_ID.to_string()) + ..LoginServerOptions::new( + config.codex_home.clone(), + CLIENT_ID.to_string(), + config.responses_originator_header.clone(), + ) }; enum LoginChatGptReply { diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index 5ce17f7a..8899b0e1 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -312,13 +312,11 @@ async fn run_ratatui_app( if should_show_onboarding { let directory_trust_decision = run_onboarding_app( OnboardingScreenArgs { - codex_home: config.codex_home.clone(), - cwd: config.cwd.clone(), show_login_screen: should_show_login_screen(login_status, &config), show_trust_screen: should_show_trust_screen, login_status, - preferred_auth_method: config.preferred_auth_method, auth_manager: auth_manager.clone(), + config: config.clone(), }, &mut tui, ) diff --git a/codex-rs/tui/src/onboarding/auth.rs b/codex-rs/tui/src/onboarding/auth.rs index c7217ac1..90b2c994 100644 --- a/codex-rs/tui/src/onboarding/auth.rs +++ b/codex-rs/tui/src/onboarding/auth.rs @@ -2,6 +2,7 @@ use codex_core::AuthManager; use codex_core::auth::CLIENT_ID; +use codex_core::config::Config; use codex_login::ServerOptions; use codex_login::ShutdownHandle; use codex_login::run_login_server; @@ -113,6 +114,7 @@ pub(crate) struct AuthModeWidget { pub login_status: LoginStatus, pub preferred_auth_method: AuthMode, pub auth_manager: Arc, + pub config: Config, } impl AuthModeWidget { @@ -314,7 +316,11 @@ impl AuthModeWidget { } self.error = None; - let opts = ServerOptions::new(self.codex_home.clone(), CLIENT_ID.to_string()); + let opts = ServerOptions::new( + self.codex_home.clone(), + CLIENT_ID.to_string(), + self.config.responses_originator_header.clone(), + ); match run_login_server(opts) { Ok(child) => { let sign_in_state = self.sign_in_state.clone(); diff --git a/codex-rs/tui/src/onboarding/onboarding_screen.rs b/codex-rs/tui/src/onboarding/onboarding_screen.rs index 5afd393c..beb96bce 100644 --- a/codex-rs/tui/src/onboarding/onboarding_screen.rs +++ b/codex-rs/tui/src/onboarding/onboarding_screen.rs @@ -1,4 +1,5 @@ use codex_core::AuthManager; +use codex_core::config::Config; use codex_core::git_info::get_git_repo_root; use crossterm::event::KeyCode; use crossterm::event::KeyEvent; @@ -21,7 +22,6 @@ use crate::tui::FrameRequester; use crate::tui::Tui; use crate::tui::TuiEvent; use color_eyre::eyre::Result; -use std::path::PathBuf; use std::sync::Arc; use std::sync::RwLock; @@ -53,26 +53,25 @@ pub(crate) struct OnboardingScreen { } pub(crate) struct OnboardingScreenArgs { - pub codex_home: PathBuf, - pub cwd: PathBuf, pub show_trust_screen: bool, pub show_login_screen: bool, pub login_status: LoginStatus, - pub preferred_auth_method: AuthMode, pub auth_manager: Arc, + pub config: Config, } impl OnboardingScreen { pub(crate) fn new(tui: &mut Tui, args: OnboardingScreenArgs) -> Self { let OnboardingScreenArgs { - codex_home, - cwd, show_trust_screen, show_login_screen, login_status, - preferred_auth_method, auth_manager, + config, } = args; + let preferred_auth_method = config.preferred_auth_method; + let cwd = config.cwd.clone(); + let codex_home = config.codex_home.clone(); let mut steps: Vec = vec![Step::Welcome(WelcomeWidget { is_logged_in: !matches!(login_status, LoginStatus::NotAuthenticated), })]; @@ -84,8 +83,9 @@ impl OnboardingScreen { sign_in_state: Arc::new(RwLock::new(SignInState::PickMode)), codex_home: codex_home.clone(), login_status, - preferred_auth_method, auth_manager, + preferred_auth_method, + config, })) } let is_git_repo = get_git_repo_root(&cwd).is_some();