mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
[codex-cli] Refresh near-expiry ChatGPT access tokens before requests (#23546)
## Summary - refresh managed ChatGPT auth during auth resolution when its access token is inside ChatGPT web's five-minute near-expiry window - cover refresh-window decisions while preserving the existing expired-token refresh path ## Why Codex already resolves managed ChatGPT auth before outbound requests and refreshes expired access tokens there. This change adjusts the existing predicate to refresh a still-valid access token once it is within the same five-minute refresh window used by ChatGPT web, avoiding a request with a token about to expire. A cross-process serialization follow-up was explored in #24663 and closed for now; we do not currently suspect cross-process refresh races are a root cause of the refresh errors under investigation. External-token, API-key, and Agent Identity auth modes remain unchanged. ## Validation - `bazel test //codex-rs/login:login-all-test` - `just fmt` runs Rust formatting successfully, then its Python SDK Ruff step cannot install `openai-codex-cli-bin==0.131.0a4` on this Linux environment because no compatible wheel is published.
This commit is contained in:
1 parent
3abf96739b
commit
e5afe5bf8c
2 files changed
+104
-5
No files matched your search
@@ -84,6 +84,7 @@ struct ChatgptAuthState {
|
||||
}
|
||||
|
||||
const TOKEN_REFRESH_INTERVAL: i64 = 8;
|
||||
const CHATGPT_ACCESS_TOKEN_REFRESH_WINDOW_MINUTES: i64 = 5;
|
||||
|
||||
const REFRESH_TOKEN_EXPIRED_MESSAGE: &str = "Your access token could not be refreshed because your refresh token has expired. Please log out and sign in again.";
|
||||
const REFRESH_TOKEN_REUSED_MESSAGE: &str = "Your access token could not be refreshed because your refresh token was already used. Please log out and sign in again.";
|
||||
@@ -1421,15 +1422,15 @@ impl AuthManager {
|
||||
}
|
||||
|
||||
/// Current cached auth (clone). May be `None` if not logged in or load failed.
|
||||
/// For stale managed ChatGPT auth, first performs a guarded reload and then
|
||||
/// refreshes only if the on-disk auth is unchanged.
|
||||
/// For managed ChatGPT auth that needs a proactive refresh, first performs
|
||||
/// a guarded reload and then refreshes only if the on-disk auth is unchanged.
|
||||
pub async fn auth(&self) -> Option<CodexAuth> {
|
||||
if let Some(auth) = self.resolve_external_api_key_auth().await {
|
||||
return Some(auth);
|
||||
}
|
||||
|
||||
let auth = self.auth_cached()?;
|
||||
if Self::is_stale_for_proactive_refresh(&auth)
|
||||
if Self::should_refresh_proactively(&auth)
|
||||
&& let Err(err) = self.refresh_token().await
|
||||
{
|
||||
tracing::error!("Failed to refresh token: {}", err);
|
||||
@@ -1808,7 +1809,7 @@ impl AuthManager {
|
||||
)
|
||||
}
|
||||
|
||||
fn is_stale_for_proactive_refresh(auth: &CodexAuth) -> bool {
|
||||
fn should_refresh_proactively(auth: &CodexAuth) -> bool {
|
||||
let chatgpt_auth = match auth {
|
||||
CodexAuth::Chatgpt(chatgpt_auth) => chatgpt_auth,
|
||||
_ => return false,
|
||||
@@ -1821,7 +1822,9 @@ impl AuthManager {
|
||||
if let Some(tokens) = auth_dot_json.tokens.as_ref()
|
||||
&& let Ok(Some(expires_at)) = parse_jwt_expiration(&tokens.access_token)
|
||||
{
|
||||
return expires_at <= Utc::now();
|
||||
return expires_at
|
||||
<= Utc::now()
|
||||
+ chrono::Duration::minutes(CHATGPT_ACCESS_TOKEN_REFRESH_WINDOW_MINUTES);
|
||||
}
|
||||
let last_refresh = match auth_dot_json.last_refresh {
|
||||
Some(last_refresh) => last_refresh,
|
||||
|
||||
Reference in new issue
Block a user