mirror of
https://github.com/openai/codex.git
synced 2026-03-19 20:36:30 +03:00
Compare commits
12 Commits
pr14989
...
auth-crate
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5acc0ccfee | ||
|
|
ff28d9cd08 | ||
|
|
c747662adc | ||
|
|
0c8b3309d8 | ||
|
|
1774364ee8 | ||
|
|
ce4382c8c5 | ||
|
|
da91e51f94 | ||
|
|
2d4c8947f9 | ||
|
|
144a0fb312 | ||
|
|
2c1d6d4e6a | ||
|
|
1412ccd128 | ||
|
|
87d9fe453a |
29
codex-rs/Cargo.lock
generated
29
codex-rs/Cargo.lock
generated
@@ -1596,6 +1596,34 @@ dependencies = [
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-auth"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"codex-app-server-protocol",
|
||||
"codex-client",
|
||||
"codex-keyring-store",
|
||||
"codex-otel",
|
||||
"codex-protocol",
|
||||
"keyring",
|
||||
"once_cell",
|
||||
"pretty_assertions",
|
||||
"reqwest",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"sha2",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-backend-client"
|
||||
version = "0.0.0"
|
||||
@@ -1840,6 +1868,7 @@ dependencies = [
|
||||
"codex-arg0",
|
||||
"codex-artifacts",
|
||||
"codex-async-utils",
|
||||
"codex-auth",
|
||||
"codex-client",
|
||||
"codex-config",
|
||||
"codex-connectors",
|
||||
|
||||
@@ -10,6 +10,7 @@ members = [
|
||||
"debug-client",
|
||||
"apply-patch",
|
||||
"arg0",
|
||||
"core/src/auth",
|
||||
"feedback",
|
||||
"codex-backend-openapi-models",
|
||||
"cloud-requirements",
|
||||
@@ -97,6 +98,7 @@ codex-app-server-test-client = { path = "app-server-test-client" }
|
||||
codex-apply-patch = { path = "apply-patch" }
|
||||
codex-arg0 = { path = "arg0" }
|
||||
codex-async-utils = { path = "async-utils" }
|
||||
codex-auth = { path = "core/src/auth" }
|
||||
codex-backend-client = { path = "backend-client" }
|
||||
codex-chatgpt = { path = "chatgpt" }
|
||||
codex-cli = { path = "cli" }
|
||||
|
||||
@@ -14,6 +14,7 @@ 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::default_client::create_client;
|
||||
use codex_login::ServerOptions;
|
||||
use codex_login::run_device_code_login;
|
||||
use codex_login::run_login_server;
|
||||
@@ -316,7 +317,11 @@ pub async fn run_login_with_device_code_fallback_to_browser(
|
||||
pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! {
|
||||
let config = load_config_or_exit(cli_config_overrides).await;
|
||||
|
||||
match CodexAuth::from_auth_storage(&config.codex_home, config.cli_auth_credentials_store_mode) {
|
||||
match CodexAuth::from_auth_storage_with_client(
|
||||
&config.codex_home,
|
||||
config.cli_auth_credentials_store_mode,
|
||||
create_client(),
|
||||
) {
|
||||
Ok(Some(auth)) => match auth.auth_mode() {
|
||||
AuthMode::ApiKey => match auth.get_token() {
|
||||
Ok(api_key) => {
|
||||
|
||||
@@ -31,6 +31,7 @@ codex-api = { workspace = true }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-apply-patch = { workspace = true }
|
||||
codex-async-utils = { workspace = true }
|
||||
codex-auth = { workspace = true }
|
||||
codex-client = { workspace = true }
|
||||
codex-connectors = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
|
||||
7
codex-rs/core/src/auth/BUILD.bazel
Normal file
7
codex-rs/core/src/auth/BUILD.bazel
Normal file
@@ -0,0 +1,7 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
codex_rust_crate(
|
||||
name = "auth",
|
||||
crate_name = "codex_auth",
|
||||
crate_srcs = glob(["*.rs"]),
|
||||
)
|
||||
39
codex-rs/core/src/auth/Cargo.toml
Normal file
39
codex-rs/core/src/auth/Cargo.toml
Normal file
@@ -0,0 +1,39 @@
|
||||
[package]
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
name = "codex-auth"
|
||||
version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
name = "codex_auth"
|
||||
path = "lib.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-client = { workspace = true }
|
||||
codex-keyring-store = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = { workspace = true }
|
||||
keyring = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
serial_test = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
||||
@@ -1,5 +1,3 @@
|
||||
mod storage;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::Utc;
|
||||
use reqwest::StatusCode;
|
||||
@@ -19,13 +17,12 @@ use codex_app_server_protocol::AuthMode as ApiAuthMode;
|
||||
use codex_otel::TelemetryAuthMode;
|
||||
use codex_protocol::config_types::ForcedLoginMethod;
|
||||
|
||||
pub use crate::auth::storage::AuthCredentialsStoreMode;
|
||||
pub use crate::auth::storage::AuthDotJson;
|
||||
use crate::auth::storage::AuthStorageBackend;
|
||||
use crate::auth::storage::create_auth_storage;
|
||||
use crate::config::Config;
|
||||
use crate::error::RefreshTokenFailedError;
|
||||
use crate::error::RefreshTokenFailedReason;
|
||||
pub use crate::storage::AuthCredentialsStoreMode;
|
||||
pub use crate::storage::AuthDotJson;
|
||||
use crate::storage::AuthStorageBackend;
|
||||
use crate::storage::create_auth_storage;
|
||||
use crate::token_data::KnownPlan as InternalKnownPlan;
|
||||
use crate::token_data::PlanType as InternalPlanType;
|
||||
use crate::token_data::TokenData;
|
||||
@@ -194,10 +191,23 @@ impl CodexAuth {
|
||||
codex_home: &Path,
|
||||
auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
) -> std::io::Result<Option<Self>> {
|
||||
load_auth(
|
||||
Self::from_auth_storage_with_client(
|
||||
codex_home,
|
||||
auth_credentials_store_mode,
|
||||
create_client(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn from_auth_storage_with_client(
|
||||
codex_home: &Path,
|
||||
auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
client: CodexHttpClient,
|
||||
) -> std::io::Result<Option<Self>> {
|
||||
load_auth_with_client(
|
||||
codex_home,
|
||||
/*enable_codex_api_key_env*/ false,
|
||||
auth_credentials_store_mode,
|
||||
client,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -335,7 +345,7 @@ impl CodexAuth {
|
||||
last_refresh: Some(Utc::now()),
|
||||
};
|
||||
|
||||
let client = crate::default_client::create_client();
|
||||
let client = create_client();
|
||||
let state = ChatgptAuthState {
|
||||
auth_dot_json: Arc::new(Mutex::new(Some(auth_dot_json))),
|
||||
client,
|
||||
@@ -351,7 +361,7 @@ impl CodexAuth {
|
||||
}
|
||||
|
||||
pub fn from_api_key(api_key: &str) -> Self {
|
||||
Self::from_api_key_with_client(api_key, crate::default_client::create_client())
|
||||
Self::from_api_key_with_client(api_key, create_client())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,11 +468,27 @@ pub fn load_auth_dot_json(
|
||||
storage.load()
|
||||
}
|
||||
|
||||
pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
|
||||
let Some(auth) = load_auth(
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct AuthConfig {
|
||||
pub codex_home: PathBuf,
|
||||
pub auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
pub forced_login_method: Option<ForcedLoginMethod>,
|
||||
pub forced_chatgpt_workspace_id: Option<String>,
|
||||
}
|
||||
|
||||
pub fn enforce_login_restrictions(config: &AuthConfig) -> std::io::Result<()> {
|
||||
enforce_login_restrictions_with_client(config, create_client())
|
||||
}
|
||||
|
||||
pub fn enforce_login_restrictions_with_client(
|
||||
config: &AuthConfig,
|
||||
client: CodexHttpClient,
|
||||
) -> std::io::Result<()> {
|
||||
let Some(auth) = load_auth_with_client(
|
||||
&config.codex_home,
|
||||
/*enable_codex_api_key_env*/ true,
|
||||
config.cli_auth_credentials_store_mode,
|
||||
config.auth_credentials_store_mode,
|
||||
client,
|
||||
)?
|
||||
else {
|
||||
return Ok(());
|
||||
@@ -486,7 +512,7 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
|
||||
return logout_with_message(
|
||||
&config.codex_home,
|
||||
message,
|
||||
config.cli_auth_credentials_store_mode,
|
||||
config.auth_credentials_store_mode,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -504,7 +530,7 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
|
||||
format!(
|
||||
"Failed to load ChatGPT credentials while enforcing workspace restrictions: {err}. Logging out."
|
||||
),
|
||||
config.cli_auth_credentials_store_mode,
|
||||
config.auth_credentials_store_mode,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -523,7 +549,7 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
|
||||
return logout_with_message(
|
||||
&config.codex_home,
|
||||
message,
|
||||
config.cli_auth_credentials_store_mode,
|
||||
config.auth_credentials_store_mode,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -562,18 +588,30 @@ fn load_auth(
|
||||
codex_home: &Path,
|
||||
enable_codex_api_key_env: bool,
|
||||
auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
) -> std::io::Result<Option<CodexAuth>> {
|
||||
load_auth_with_client(
|
||||
codex_home,
|
||||
enable_codex_api_key_env,
|
||||
auth_credentials_store_mode,
|
||||
create_client(),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_auth_with_client(
|
||||
codex_home: &Path,
|
||||
enable_codex_api_key_env: bool,
|
||||
auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
client: CodexHttpClient,
|
||||
) -> std::io::Result<Option<CodexAuth>> {
|
||||
let build_auth = |auth_dot_json: AuthDotJson, storage_mode| {
|
||||
let client = crate::default_client::create_client();
|
||||
CodexAuth::from_auth_dot_json(codex_home, auth_dot_json, storage_mode, client)
|
||||
CodexAuth::from_auth_dot_json(codex_home, auth_dot_json, storage_mode, client.clone())
|
||||
};
|
||||
|
||||
// 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() {
|
||||
let client = crate::default_client::create_client();
|
||||
return Ok(Some(CodexAuth::from_api_key_with_client(
|
||||
api_key.as_str(),
|
||||
client,
|
||||
client.clone(),
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -1077,7 +1115,7 @@ impl AuthManager {
|
||||
}
|
||||
|
||||
/// Create an AuthManager with a specific CodexAuth, for testing only.
|
||||
pub(crate) fn from_auth_for_testing(auth: CodexAuth) -> Arc<Self> {
|
||||
pub fn from_auth_for_testing(auth: CodexAuth) -> Arc<Self> {
|
||||
let cached = CachedAuth {
|
||||
auth: Some(auth),
|
||||
external_refresher: None,
|
||||
@@ -1093,10 +1131,7 @@ impl AuthManager {
|
||||
}
|
||||
|
||||
/// Create an AuthManager with a specific CodexAuth and codex home, for testing only.
|
||||
pub(crate) fn from_auth_for_testing_with_home(
|
||||
auth: CodexAuth,
|
||||
codex_home: PathBuf,
|
||||
) -> Arc<Self> {
|
||||
pub fn from_auth_for_testing_with_home(auth: CodexAuth, codex_home: PathBuf) -> Arc<Self> {
|
||||
let cached = CachedAuth {
|
||||
auth: Some(auth),
|
||||
external_refresher: None,
|
||||
@@ -1449,3 +1484,7 @@ impl AuthManager {
|
||||
#[cfg(test)]
|
||||
#[path = "auth_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
fn create_client() -> CodexHttpClient {
|
||||
CodexHttpClient::new(reqwest::Client::new())
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
use super::*;
|
||||
use crate::auth::storage::FileAuthStorage;
|
||||
use crate::auth::storage::get_auth_file;
|
||||
use crate::config::Config;
|
||||
use crate::config::ConfigBuilder;
|
||||
use crate::storage::FileAuthStorage;
|
||||
use crate::storage::get_auth_file;
|
||||
use crate::token_data::IdTokenInfo;
|
||||
use crate::token_data::KnownPlan as InternalKnownPlan;
|
||||
use crate::token_data::PlanType as InternalPlanType;
|
||||
@@ -260,15 +258,13 @@ async fn build_config(
|
||||
codex_home: &Path,
|
||||
forced_login_method: Option<ForcedLoginMethod>,
|
||||
forced_chatgpt_workspace_id: Option<String>,
|
||||
) -> Config {
|
||||
let mut config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.to_path_buf())
|
||||
.build()
|
||||
.await
|
||||
.expect("config should load");
|
||||
config.forced_login_method = forced_login_method;
|
||||
config.forced_chatgpt_workspace_id = forced_chatgpt_workspace_id;
|
||||
config
|
||||
) -> AuthConfig {
|
||||
AuthConfig {
|
||||
codex_home: codex_home.to_path_buf(),
|
||||
auth_credentials_store_mode: AuthCredentialsStoreMode::File,
|
||||
forced_login_method,
|
||||
forced_chatgpt_workspace_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Use sparingly.
|
||||
25
codex-rs/core/src/auth/error.rs
Normal file
25
codex-rs/core/src/auth/error.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
#[error("{message}")]
|
||||
pub struct RefreshTokenFailedError {
|
||||
pub reason: RefreshTokenFailedReason,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl RefreshTokenFailedError {
|
||||
pub fn new(reason: RefreshTokenFailedReason, message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
reason,
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RefreshTokenFailedReason {
|
||||
Expired,
|
||||
Exhausted,
|
||||
Revoked,
|
||||
Other,
|
||||
}
|
||||
10
codex-rs/core/src/auth/lib.rs
Normal file
10
codex-rs/core/src/auth/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
pub mod error;
|
||||
mod storage;
|
||||
pub mod token_data;
|
||||
mod util;
|
||||
|
||||
mod auth;
|
||||
|
||||
pub use auth::*;
|
||||
pub use error::RefreshTokenFailedError;
|
||||
pub use error::RefreshTokenFailedReason;
|
||||
@@ -27,7 +27,7 @@ pub struct IdTokenInfo {
|
||||
/// The ChatGPT subscription plan type
|
||||
/// (e.g., "free", "plus", "pro", "business", "enterprise", "edu").
|
||||
/// (Note: values may vary by backend.)
|
||||
pub(crate) chatgpt_plan_type: Option<PlanType>,
|
||||
pub chatgpt_plan_type: Option<PlanType>,
|
||||
/// ChatGPT user identifier associated with the token, if present.
|
||||
pub chatgpt_user_id: Option<String>,
|
||||
/// Organization/workspace identifier associated with the token, if present.
|
||||
@@ -55,13 +55,13 @@ impl IdTokenInfo {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub(crate) enum PlanType {
|
||||
pub enum PlanType {
|
||||
Known(KnownPlan),
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
impl PlanType {
|
||||
pub(crate) fn from_raw_value(raw: &str) -> Self {
|
||||
pub fn from_raw_value(raw: &str) -> Self {
|
||||
match raw.to_ascii_lowercase().as_str() {
|
||||
"free" => Self::Known(KnownPlan::Free),
|
||||
"go" => Self::Known(KnownPlan::Go),
|
||||
@@ -78,7 +78,7 @@ impl PlanType {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub(crate) enum KnownPlan {
|
||||
pub enum KnownPlan {
|
||||
Free,
|
||||
Go,
|
||||
Plus,
|
||||
16
codex-rs/core/src/auth/util.rs
Normal file
16
codex-rs/core/src/auth/util.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use tracing::debug;
|
||||
|
||||
pub(crate) fn try_parse_error_message(text: &str) -> String {
|
||||
debug!("Parsing server error response: {}", text);
|
||||
let json = serde_json::from_str::<serde_json::Value>(text).unwrap_or_default();
|
||||
if let Some(error) = json.get("error")
|
||||
&& let Some(message) = error.get("message")
|
||||
&& let Some(message_str) = message.as_str()
|
||||
{
|
||||
return message_str.to_string();
|
||||
}
|
||||
if text.is_empty() {
|
||||
return "Unknown error".to_string();
|
||||
}
|
||||
text.to_string()
|
||||
}
|
||||
@@ -9,6 +9,8 @@ use chrono::Datelike;
|
||||
use chrono::Local;
|
||||
use chrono::Utc;
|
||||
use codex_async_utils::CancelErr;
|
||||
pub use codex_auth::RefreshTokenFailedError;
|
||||
pub use codex_auth::RefreshTokenFailedReason;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::CodexErrorInfo;
|
||||
use codex_protocol::protocol::ErrorEvent;
|
||||
@@ -261,30 +263,6 @@ impl std::fmt::Display for ResponseStreamFailed {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
#[error("{message}")]
|
||||
pub struct RefreshTokenFailedError {
|
||||
pub reason: RefreshTokenFailedReason,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl RefreshTokenFailedError {
|
||||
pub fn new(reason: RefreshTokenFailedReason, message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
reason,
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RefreshTokenFailedReason {
|
||||
Expired,
|
||||
Exhausted,
|
||||
Revoked,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnexpectedResponseError {
|
||||
pub status: StatusCode,
|
||||
|
||||
@@ -10,7 +10,7 @@ pub mod api_bridge;
|
||||
mod apply_patch;
|
||||
mod apps;
|
||||
mod arc_monitor;
|
||||
pub mod auth;
|
||||
pub use codex_auth as auth;
|
||||
mod auth_env_telemetry;
|
||||
mod client;
|
||||
mod client_common;
|
||||
@@ -76,7 +76,7 @@ mod shell_detect;
|
||||
mod stream_events_utils;
|
||||
pub mod test_support;
|
||||
mod text_encoding;
|
||||
pub mod token_data;
|
||||
pub use codex_auth::token_data;
|
||||
mod truncate;
|
||||
mod unified_exec;
|
||||
pub mod windows_sandbox;
|
||||
|
||||
@@ -45,7 +45,8 @@ use codex_cloud_requirements::cloud_requirements_loader;
|
||||
use codex_core::AuthManager;
|
||||
use codex_core::LMSTUDIO_OSS_PROVIDER_ID;
|
||||
use codex_core::OLLAMA_OSS_PROVIDER_ID;
|
||||
use codex_core::auth::enforce_login_restrictions;
|
||||
use codex_core::auth::AuthConfig;
|
||||
use codex_core::auth::enforce_login_restrictions_with_client;
|
||||
use codex_core::check_execpolicy_for_warnings;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
@@ -56,6 +57,7 @@ use codex_core::config::resolve_oss_provider;
|
||||
use codex_core::config_loader::ConfigLoadError;
|
||||
use codex_core::config_loader::LoaderOverrides;
|
||||
use codex_core::config_loader::format_config_error_with_source;
|
||||
use codex_core::default_client::create_client;
|
||||
use codex_core::format_exec_policy_error_with_source;
|
||||
use codex_core::git_info::get_git_repo_root;
|
||||
use codex_feedback::CodexFeedback;
|
||||
@@ -381,7 +383,15 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
|
||||
|
||||
set_default_client_residency_requirement(config.enforce_residency.value());
|
||||
|
||||
if let Err(err) = enforce_login_restrictions(&config) {
|
||||
if let Err(err) = enforce_login_restrictions_with_client(
|
||||
&AuthConfig {
|
||||
codex_home: config.codex_home.clone(),
|
||||
auth_credentials_store_mode: config.cli_auth_credentials_store_mode,
|
||||
forced_login_method: config.forced_login_method,
|
||||
forced_chatgpt_workspace_id: config.forced_chatgpt_workspace_id.clone(),
|
||||
},
|
||||
create_client(),
|
||||
) {
|
||||
eprintln!("{err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ use codex_core::INTERACTIVE_SESSION_SOURCES;
|
||||
use codex_core::RolloutRecorder;
|
||||
use codex_core::ThreadSortKey;
|
||||
use codex_core::auth::AuthMode;
|
||||
use codex_core::auth::enforce_login_restrictions;
|
||||
use codex_core::check_execpolicy_for_warnings;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
@@ -26,6 +25,7 @@ use codex_core::config_loader::CloudRequirementsLoader;
|
||||
use codex_core::config_loader::ConfigLoadError;
|
||||
use codex_core::config_loader::LoaderOverrides;
|
||||
use codex_core::config_loader::format_config_error_with_source;
|
||||
use codex_core::default_client::create_client;
|
||||
use codex_core::default_client::set_default_client_residency_requirement;
|
||||
use codex_core::find_thread_path_by_id_str;
|
||||
use codex_core::find_thread_path_by_name_str;
|
||||
@@ -1155,7 +1155,11 @@ fn get_login_status(config: &Config) -> LoginStatus {
|
||||
// Reading the OpenAI API key is an async operation because it may need
|
||||
// to refresh the token. Block on it.
|
||||
let codex_home = config.codex_home.clone();
|
||||
match CodexAuth::from_auth_storage(&codex_home, config.cli_auth_credentials_store_mode) {
|
||||
match CodexAuth::from_auth_storage_with_client(
|
||||
&codex_home,
|
||||
config.cli_auth_credentials_store_mode,
|
||||
create_client(),
|
||||
) {
|
||||
Ok(Some(auth)) => LoginStatus::AuthMode(auth.auth_mode()),
|
||||
Ok(None) => LoginStatus::NotAuthenticated,
|
||||
Err(err) => {
|
||||
|
||||
@@ -7,6 +7,7 @@ use codex_client::build_reqwest_client_with_custom_ca;
|
||||
use codex_core::auth::AuthCredentialsStoreMode;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core::default_client::create_client;
|
||||
use codex_core::default_client::get_codex_user_agent;
|
||||
use codex_login::AuthMode;
|
||||
use codex_login::CodexAuth;
|
||||
@@ -926,9 +927,13 @@ fn normalize_chatgpt_base_url(input: &str) -> String {
|
||||
|
||||
async fn resolve_auth() -> Result<TranscriptionAuthContext, String> {
|
||||
let codex_home = find_codex_home().map_err(|e| format!("failed to find codex home: {e}"))?;
|
||||
let auth = CodexAuth::from_auth_storage(&codex_home, AuthCredentialsStoreMode::Auto)
|
||||
.map_err(|e| format!("failed to read auth.json: {e}"))?
|
||||
.ok_or_else(|| "No Codex auth is configured; please run `codex login`".to_string())?;
|
||||
let auth = CodexAuth::from_auth_storage_with_client(
|
||||
&codex_home,
|
||||
AuthCredentialsStoreMode::Auto,
|
||||
create_client(),
|
||||
)
|
||||
.map_err(|e| format!("failed to read auth.json: {e}"))?
|
||||
.ok_or_else(|| "No Codex auth is configured; please run `codex login`".to_string())?;
|
||||
|
||||
let chatgpt_account_id = auth.get_account_id();
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ use codex_app_server_protocol::ThreadListParams;
|
||||
use codex_app_server_protocol::ThreadSortKey as AppServerThreadSortKey;
|
||||
use codex_app_server_protocol::ThreadSourceKind;
|
||||
use codex_cloud_requirements::cloud_requirements_loader_for_storage;
|
||||
use codex_core::auth::enforce_login_restrictions;
|
||||
use codex_core::auth::AuthConfig;
|
||||
use codex_core::auth::enforce_login_restrictions_with_client;
|
||||
use codex_core::check_execpolicy_for_warnings;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
@@ -33,6 +34,7 @@ use codex_core::config_loader::CloudRequirementsLoader;
|
||||
use codex_core::config_loader::ConfigLoadError;
|
||||
use codex_core::config_loader::LoaderOverrides;
|
||||
use codex_core::config_loader::format_config_error_with_source;
|
||||
use codex_core::default_client::create_client;
|
||||
use codex_core::default_client::set_default_client_residency_requirement;
|
||||
use codex_core::format_exec_policy_error_with_source;
|
||||
use codex_core::path_utils;
|
||||
@@ -776,7 +778,15 @@ pub async fn run_main(
|
||||
|
||||
if matches!(app_server_target, AppServerTarget::Embedded) {
|
||||
#[allow(clippy::print_stderr)]
|
||||
if let Err(err) = enforce_login_restrictions(&config) {
|
||||
if let Err(err) = enforce_login_restrictions_with_client(
|
||||
&AuthConfig {
|
||||
codex_home: config.codex_home.clone(),
|
||||
auth_credentials_store_mode: config.cli_auth_credentials_store_mode,
|
||||
forced_login_method: config.forced_login_method,
|
||||
forced_chatgpt_workspace_id: config.forced_chatgpt_workspace_id.clone(),
|
||||
},
|
||||
create_client(),
|
||||
) {
|
||||
eprintln!("{err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use codex_client::build_reqwest_client_with_custom_ca;
|
||||
use codex_core::auth::AuthCredentialsStoreMode;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core::default_client::create_client;
|
||||
use codex_core::default_client::get_codex_user_agent;
|
||||
use codex_login::AuthMode;
|
||||
use codex_login::CodexAuth;
|
||||
@@ -764,9 +765,13 @@ fn normalize_chatgpt_base_url(input: &str) -> String {
|
||||
|
||||
async fn resolve_auth() -> Result<TranscriptionAuthContext, String> {
|
||||
let codex_home = find_codex_home().map_err(|e| format!("failed to find codex home: {e}"))?;
|
||||
let auth = CodexAuth::from_auth_storage(&codex_home, AuthCredentialsStoreMode::Auto)
|
||||
.map_err(|e| format!("failed to read auth.json: {e}"))?
|
||||
.ok_or_else(|| "No Codex auth is configured; please run `codex login`".to_string())?;
|
||||
let auth = CodexAuth::from_auth_storage_with_client(
|
||||
&codex_home,
|
||||
AuthCredentialsStoreMode::Auto,
|
||||
create_client(),
|
||||
)
|
||||
.map_err(|e| format!("failed to read auth.json: {e}"))?
|
||||
.ok_or_else(|| "No Codex auth is configured; please run `codex login`".to_string())?;
|
||||
|
||||
let chatgpt_account_id = auth.get_account_id();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user