mirror of
https://github.com/openai/codex.git
synced 2026-09-06 15:29:32 +00:00
[codex-login] clear invalidated auth without account id [ci changed_files]
This commit is contained in:
@@ -360,6 +360,41 @@ async fn invalidated_access_token_logout_clears_cached_auth() {
|
||||
assert!(!codex_home.path().join("auth.json").exists());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalidated_access_token_logout_clears_cached_auth_without_account_id() {
|
||||
let codex_home = tempdir().unwrap();
|
||||
write_auth_file(
|
||||
AuthFileParams {
|
||||
openai_api_key: None,
|
||||
chatgpt_plan_type: Some("pro".to_string()),
|
||||
chatgpt_account_id: None,
|
||||
},
|
||||
codex_home.path(),
|
||||
)
|
||||
.expect("failed to write auth file");
|
||||
let manager = AuthManager::shared(
|
||||
codex_home.path().to_path_buf(),
|
||||
/*enable_codex_api_key_env*/ false,
|
||||
AuthCredentialsStoreMode::File,
|
||||
/*chatgpt_base_url*/ None,
|
||||
)
|
||||
.await;
|
||||
let recovery = manager.unauthorized_recovery();
|
||||
|
||||
let failed = recovery
|
||||
.handle_invalidated_access_token_auth()
|
||||
.await
|
||||
.expect_err("unchanged revoked auth without an account id should force login");
|
||||
|
||||
assert_eq!(failed.reason, RefreshTokenFailedReason::Revoked);
|
||||
assert_eq!(
|
||||
failed.message,
|
||||
"Your ChatGPT session is no longer valid. Please sign in again."
|
||||
);
|
||||
assert!(manager.auth_cached().is_none());
|
||||
assert!(!codex_home.path().join("auth.json").exists());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalidated_access_token_preserves_reloaded_auth() {
|
||||
let codex_home = tempdir().unwrap();
|
||||
|
||||
@@ -1265,14 +1265,27 @@ impl UnauthorizedRecovery {
|
||||
pub async fn handle_invalidated_access_token_auth(
|
||||
&self,
|
||||
) -> Result<UnauthorizedRecoveryStepResult, RefreshTokenFailedError> {
|
||||
match self
|
||||
.manager
|
||||
.reload_if_account_id_matches(self.expected_account_id.as_deref())
|
||||
.await
|
||||
{
|
||||
ReloadOutcome::ReloadedChanged => Ok(UnauthorizedRecoveryStepResult {
|
||||
auth_state_changed: Some(true),
|
||||
}),
|
||||
let reload_outcome = match self.expected_account_id.as_deref() {
|
||||
Some(expected_account_id) => {
|
||||
self.manager
|
||||
.reload_if_account_id_matches(Some(expected_account_id))
|
||||
.await
|
||||
}
|
||||
None => self.manager.reload_if_auth_snapshot_changed().await,
|
||||
};
|
||||
|
||||
match reload_outcome {
|
||||
ReloadOutcome::ReloadedChanged => {
|
||||
if self.manager.auth_cached().is_none() {
|
||||
return Err(RefreshTokenFailedError::new(
|
||||
RefreshTokenFailedReason::Revoked,
|
||||
ACCESS_TOKEN_INVALIDATED_MESSAGE.to_string(),
|
||||
));
|
||||
}
|
||||
Ok(UnauthorizedRecoveryStepResult {
|
||||
auth_state_changed: Some(true),
|
||||
})
|
||||
}
|
||||
ReloadOutcome::ReloadedNoChange => {
|
||||
let message = match self.manager.logout().await {
|
||||
Ok(_) => ACCESS_TOKEN_INVALIDATED_MESSAGE.to_string(),
|
||||
@@ -1532,6 +1545,20 @@ impl AuthManager {
|
||||
}
|
||||
}
|
||||
|
||||
async fn reload_if_auth_snapshot_changed(&self) -> ReloadOutcome {
|
||||
let new_auth = self.load_auth_from_storage().await;
|
||||
let cached_before_reload = self.auth_cached();
|
||||
let auth_changed =
|
||||
!Self::auths_equal_for_refresh(cached_before_reload.as_ref(), new_auth.as_ref());
|
||||
if !auth_changed {
|
||||
return ReloadOutcome::ReloadedNoChange;
|
||||
}
|
||||
|
||||
tracing::info!("Reloading auth because the persisted auth snapshot changed.");
|
||||
self.set_cached_auth(new_auth);
|
||||
ReloadOutcome::ReloadedChanged
|
||||
}
|
||||
|
||||
fn auths_equal_for_refresh(a: Option<&CodexAuth>, b: Option<&CodexAuth>) -> bool {
|
||||
match (a, b) {
|
||||
(None, None) => true,
|
||||
|
||||
Reference in New Issue
Block a user