use codex_common::CliConfigOverrides; use codex_core::CodexAuth; use codex_core::auth::CLIENT_ID; use codex_core::auth::login_with_api_key; use codex_core::auth::logout; use codex_core::config::Config; use codex_core::config::ConfigOverrides; use codex_login::ServerOptions; use codex_login::run_device_code_login; use codex_login::run_login_server; use codex_protocol::mcp_protocol::AuthMode; 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()); let server = run_login_server(opts)?; eprintln!( "Starting local login server on http://localhost:{}.\nIf your browser did not open, navigate to this URL to authenticate:\n\n{}", server.actual_port, server.auth_url, ); server.block_until_done().await } 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 { Ok(_) => { eprintln!("Successfully logged in"); std::process::exit(0); } Err(e) => { eprintln!("Error logging in: {e}"); std::process::exit(1); } } } pub async fn run_login_with_api_key( cli_config_overrides: CliConfigOverrides, api_key: String, ) -> ! { let config = load_config_or_exit(cli_config_overrides); match login_with_api_key(&config.codex_home, &api_key) { Ok(_) => { eprintln!("Successfully logged in"); std::process::exit(0); } Err(e) => { eprintln!("Error logging in: {e}"); std::process::exit(1); } } } /// Login using the OAuth device code flow. pub async fn run_login_with_device_code( cli_config_overrides: CliConfigOverrides, issuer_base_url: Option, client_id: Option, ) -> ! { let config = load_config_or_exit(cli_config_overrides); let mut opts = ServerOptions::new( config.codex_home, client_id.unwrap_or(CLIENT_ID.to_string()), ); if let Some(iss) = issuer_base_url { opts.issuer = iss; } match run_device_code_login(opts).await { Ok(()) => { eprintln!("Successfully logged in"); std::process::exit(0); } Err(e) => { eprintln!("Error logging in with device code: {e}"); std::process::exit(1); } } } pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! { let config = load_config_or_exit(cli_config_overrides); match CodexAuth::from_codex_home(&config.codex_home) { Ok(Some(auth)) => match auth.mode { AuthMode::ApiKey => match auth.get_token().await { Ok(api_key) => { eprintln!("Logged in using an API key - {}", safe_format_key(&api_key)); std::process::exit(0); } Err(e) => { eprintln!("Unexpected error retrieving API key: {e}"); std::process::exit(1); } }, AuthMode::ChatGPT => { eprintln!("Logged in using ChatGPT"); std::process::exit(0); } }, Ok(None) => { eprintln!("Not logged in"); std::process::exit(1); } Err(e) => { eprintln!("Error checking login status: {e}"); std::process::exit(1); } } } pub async fn run_logout(cli_config_overrides: CliConfigOverrides) -> ! { let config = load_config_or_exit(cli_config_overrides); match logout(&config.codex_home) { Ok(true) => { eprintln!("Successfully logged out"); std::process::exit(0); } Ok(false) => { eprintln!("Not logged in"); std::process::exit(0); } Err(e) => { eprintln!("Error logging out: {e}"); std::process::exit(1); } } } fn load_config_or_exit(cli_config_overrides: CliConfigOverrides) -> Config { let cli_overrides = match cli_config_overrides.parse_overrides() { Ok(v) => v, Err(e) => { eprintln!("Error parsing -c overrides: {e}"); std::process::exit(1); } }; let config_overrides = ConfigOverrides::default(); match Config::load_with_cli_overrides(cli_overrides, config_overrides) { Ok(config) => config, Err(e) => { eprintln!("Error loading configuration: {e}"); std::process::exit(1); } } } fn safe_format_key(key: &str) -> String { if key.len() <= 13 { return "***".to_string(); } let prefix = &key[..8]; let suffix = &key[key.len() - 5..]; format!("{prefix}***{suffix}") } #[cfg(test)] mod tests { use super::safe_format_key; #[test] fn formats_long_key() { let key = "sk-proj-1234567890ABCDE"; assert_eq!(safe_format_key(key), "sk-proj-***ABCDE"); } #[test] fn short_key_returns_stars() { let key = "sk-proj-12345"; assert_eq!(safe_format_key(key), "***"); } }