ChatGPT-Login und Authentifizierung
Bevor codex ein Modell aufrufen kann, müssen OpenAI-Credentials vorliegen. Diese Schicht erledigt alles zwischen „Benutzer tippt codex login" und „auth.json wird in $CODEX_HOME geschrieben": Browser-OAuth, PKCE, Device Code, API key, Access Token — fünf Einstiege, die sich ein und dieselbe CodexAuth-Enum und denselben AuthManager-Zustandsautomat teilen. Der login/-Crate übernimmt das reine Authentifizierungsprotokoll, cli/src/login.rs ist dafür zuständig, die Protokollergebnisse auf die Platte zu schreiben und auf stderr Feedback zu geben.
Verantwortlichkeiten
- Einheitliche Credentials-Formen: Die
CodexAuth-Enum deckt sieben Modi ab — API key, ChatGPT-OAuth, externe ChatGPT-Tokens, agent identity JWT, personal access token (PAT), Bedrock API key.codex-rs/login/src/auth/manager.rs:71-79 - Browser-OAuth + PKCE:
run_login_serverstartet lokal einen Callback-Server, erzeugt PKCE-Pair und state, setzt dieauth_urlfür den Browser-Sprung zusammen und wartet auf den Callback, um code gegen token zu tauschen.codex-rs/login/src/server.rs:151-197 - Device-Code-Flow:
run_device_code_loginholt zunächst bei/deviceauth/usercodeeinen user_code, gibt im Terminal eine verification_url zum Eingeben im Browser aus und pollt dann den Token-Endpunkt.codex-rs/login/src/device_code_auth.rs:234-238 - CLI-Einstiegs-Wrapper:
run_login_with_chatgpt/run_login_with_api_key/run_login_with_access_token/run_login_with_device_codeentfernen vor dem Lauf alte Credentials, richten eine Datei-Logging-Schicht ein, prüfen gegenforced_login_method, ob der Pfad erlaubt ist, und rufen am Endestd::process::exitauf.codex-rs/cli/src/login.rs:167-196 - Auth-Reload und Widerruf:
AuthManager::reloadliestauth.jsonnach, nachdem ein externer Prozess den Token aktualisiert hat;logout_with_revokeruft den OAuth-Revoke-Endpunkt auf und löscht anschließend die lokalen Credentials.codex-rs/login/src/auth/manager.rs:877-925
Entwurfsbeweggründe
Codex unterstützte ursprünglich nur zwei Pfade: ChatGPT-Browser-Login und API key. Der ChatGPT-Login läuft über OAuth + PKCE: lokal wird ein Callback-Server gestartet, code_verifier / code_challenge erzeugt, der Browser springt auf, OpenAI ruft http://localhost:PORT/auth/callback?code=...&state=... zurück; der Server nutzt state gegen CSRF und tauscht mit code_verifier den Token. Dieser Ablauf braucht zwingend einen lokalen Browser; in Remote-SSH-Umgebungen funktioniert er nicht.
Daher kam der Device-Code-Flow hinzu (device_code_auth.rs): Der Benutzer sieht im Terminal https://chatgpt.com/device und einen user_code, den er in einem beliebigen Browser eingibt. run_login_with_device_code_fallback_to_browser baut zusätzlich einen Fallback: zuerst Device Code versuchen; liefert der Server 404 (Backend hat Device Auth nicht aktiviert), wird auf den Browser-Server-Flow zurückgefallen.
CodexAuth ist eine Enum und kein Trait-Objekt, weil die Datenstrukturen der Credential-Modi stark voneinander abweichen — API key ist nur ein String, ChatGPT-OAuth besteht aus dem Tripel access_token / refresh_token / id_token, agent identity ist ein JWT. Eine Enum macht Matching wie auth_mode() sofort verständlich; ein neuer Modus ist einfach eine neue Variante statt einer neuen vtable.
AgentIdentityAuthPolicy::JwtOnly vs. ChatGptAuth — diese beiden Strategien entscheiden, ob beim bereits mit ChatGPT eingeloggeten Benutzer automatisch eine agent identity registriert wird. ChatGptAuth erlaubt standardmäßig dieses implizite Upgrade, sodass long-running tasks nicht separat eine agent identity einloggen müssen.
Wichtige Dateien
codex-rs/login/src/auth/manager.rs:71-79 — pub enum CodexAuth, Wurzel der sieben Credential-Modi.codex-rs/login/src/auth/manager.rs:929-977 — login_with_access_token, leitet je nach Token-Form auf PAT oder agent identity JWT weiter.codex-rs/login/src/server.rs:68-148 — ServerOptions / LoginServer / ShutdownHandle, Konfiguration und Lebenszyklus des Browser-OAuth-Servers.codex-rs/login/src/device_code_auth.rs:20-34 — DeviceCode-Struktur, hält verification_url, user_code, device_auth_id, Polling-Intervall.codex-rs/cli/src/login.rs:52-111 — init_login_file_logging, richtet eine minimale file-backed tracing-Schicht für codex-login.log ein; bewusst nicht der schwere Telemetrie-Stack der TUI.codex-rs/cli/src/login.rs:119-135 — clear_existing_auth_before_login, vor dem Login erst logout, damit keine alten Token übrig bleiben.codex-rs/tui/src/local_chatgpt_auth.rs:17-59 — load_local_chatgpt_auth, TUI-Testhilfe: extrahiert ChatGPT access_token / account_id / plan_type aus der lokalen auth.json.CodexAuth ist die einzige Wahrheitsquelle für Credentials; downstream matchen client.rs, provider und Telemetrie alles aus ihr heraus. Ein neuer Credential-Typ bedeutet: Variante anlegen und an den Stellen einen neuen match arm hinzufügen.
// login/src/auth/manager.rs:71-79 — 七种凭据模式
pub enum CodexAuth {
ApiKey(ApiKeyAuth),
Chatgpt(ChatgptAuth),
ChatgptAuthTokens(ChatgptAuthTokens),
Headers(AuthHeaders),
AgentIdentity(AgentIdentityAuth),
PersonalAccessToken(PersonalAccessTokenAuth),
BedrockApiKey(BedrockApiKeyAuth),
}run_login_with_chatgpt ist der dünne Wrapper auf CLI-Ebene: config laden → Datei-Logging einrichten → prüfen, ob forced_login_method den ChatGPT-Pfad verbietet → alte Credentials löschen → Callback-Server starten. Beachten: der Rückgabetyp ist ! (never), alle Ausgänge sind process::exit; der Aufrufer läuft danach nicht weiter.
// cli/src/login.rs:167-184 — ChatGPT 登录入口,薄包装 + 硬退出
pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) -> ! {
let config = load_config_or_exit(cli_config_overrides).await;
let _login_log_guard = init_login_file_logging(&config);
tracing::info!("starting browser login flow");
if matches!(config.forced_login_method, Some(ForcedLoginMethod::Api)) {
eprintln!("{CHATGPT_LOGIN_DISABLED_MESSAGE}");
std::process::exit(1);
}
let forced_chatgpt_workspace_id = config.forced_chatgpt_workspace_id.clone();
match login_with_chatgpt(
config.codex_home.to_path_buf(),
forced_chatgpt_workspace_id,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
config.auth_route_config(),
).await { /* Ok/Err 分别 exit */ }
}login_with_access_token ist typisch für „automatische Dispatch nach Token-Form" — derselbe --with-access-token-Flag kommt herein, aber intern wird anhand der JWT-Struktur entschieden, ob der PAT-Pfad oder der agent-identity-JWT-Pfad genommen wird. Beim Schreiben des AuthDotJson unterscheidet sich auch das Feld auth_mode, sodass ältere codex-Versionen beim Zurückrollen korrekt deserialisieren können.
// login/src/auth/manager.rs:929-970 — access token 自动分派 PAT vs AgentIdentity
pub async fn login_with_access_token(/* ... */) -> std::io::Result<()> {
let auth_dot_json = match classify_codex_access_token(access_token) {
CodexAccessToken::PersonalAccessToken(access_token) => {
let auth = PersonalAccessTokenAuth::load(access_token, auth_route_config).await?;
ensure_personal_access_token_workspace_allowed(forced_chatgpt_workspace_id, &auth)?;
AuthDotJson { auth_mode: None, personal_access_token: Some(access_token.to_string()), .. }
}
CodexAccessToken::AgentIdentityJwt(jwt) => {
verified_record_from_jwt(jwt, &base_url, auth_route_config).await?;
AuthDotJson { auth_mode: Some(AuthMode::AgentIdentity),
agent_identity: Some(AgentIdentityStorage::Jwt(jwt.to_string())), .. }
}
};
save_auth(codex_home, &auth_dot_json, auth_credentials_store_mode, keyring_backend_kind)
}Datenfluss
Grenzen und Fehler
forced_login_methodgegenseitig ausschließend: Administratoren können erzwingen, dass nur API oder nur ChatGPT erlaubt ist; die CLI bricht bei Verstoß direkt auf stderr mit exit 1 ab, statt erst mitten im OAuth abgewiesen zu werden.codex-rs/cli/src/login.rs:172-175- Fallback bei nicht unterstütztem Device Code:
run_login_with_device_code_fallback_to_browserversucht zuerst Device Code; liefert dieserErrorKind::NotFound(Backend hat es nicht aktiviert), wird automatisch auf den Browser-Server-Flow zurückgefallen; andere Fehler gelten als echter Fehlschlag.codex-rs/cli/src/login.rs:389-419 - Dateirechte von
auth.json: Auf Unix erzwingtOpenOptionsExt::mode(0o600), dass nur der Eigentümer lesen darf, damit Credentials für Gruppenmitglieder nicht sichtbar sind.codex-rs/cli/src/login.rs:69-78 - PAT-Workspace-Beschränkung:
ensure_personal_access_token_workspace_allowedprüft beim PAT-Login, obforced_chatgpt_workspace_idpasst, und verhindert so workspace-übergreifenden PAT-Missbrauch.codex-rs/login/src/auth/manager.rs:979-985
Zusammenfassung
Der login/-Cate vereinheitlicht fünf Login-Einstiege in der CodexAuth-Enum und dem AuthManager-Zustandsautomat: Browser-OAuth + PKCE für lokal, Device Code für Remote, API key / PAT / agent identity JWT für Automatisierungsszenarien. cli/src/login.rs ist ein dünner Wrapper, der Datei-Logging einrichtet, alte Credentials löscht und an forced_login_method vorbeikontrolliert; alle Ausgänge sind process::exit. Nach dem Schreiben ist auth.json die Credential-Quelle für alle weiteren Modellrequests; siehe LLM-Client und Responses API. Nach Abschluss des Logins geht der Benutzer in die TUI oder läuft codex exec; siehe CLI-Einstieg und Subcommand-Dispatch.