Windows Desktop: fresh ChatGPT refresh token is rejected as refresh_token_invalidated on its first isolated refresh, causing false logout after unrelated 401
What version of the Codex App are you using (From “About Codex” dialog)?
26.818.3698.0
What subscription do you have?
ChatGPT Plus
What platform is your computer?
Windows 11 x64
What issue are you seeing?
Codex Desktop repeatedly returns to the ChatGPT login screen even though the current OAuth access token is still valid.
The account is confirmed to be a ChatGPT Plus personal account:
/backend-api/wham/accounts/checkreturns HTTP 200plan_type = plusstructure = personal- local Codex app-server
account/readreturnsplanType = plus
The reproducible failure chain in the Desktop logs is:
- Desktop starts in a valid authenticated state:
authenticatedAccountPresent=true
- Desktop sends:
GET /backend-api/accounts/{account_id}/settings
- That request returns HTTP 401 while:
hadToken=true
tokenSource=cached
- The generic auth wrapper treats the 401 as an authentication failure and forces:
refreshToken=true
- The refresh fails and app-server reports:
authMethod=chatgpt
hasToken=false
nullReason=auth_token_missing
- Account lookup then becomes:
authenticatedAccountPresent=false
failureType=account_info_token_unavailable
- Desktop returns to the ChatGPT login screen.
However, after Desktop has already returned to the login screen, the same access token stored in ~/.codex/auth.json still successfully authenticates against:
GET /backend-api/wham/usage
and returns HTTP 200.
Therefore this appears to be a false/in-memory logout rather than an actual access-token expiration.
An earlier occurrence of the /accounts/{account_id}/settings 401 returned:
Must use workspace account for this operation
even though the account is confirmed as plus / personal.
I also performed a strict isolated refresh-token test. After a completely fresh ChatGPT login, with Desktop closed, zero other Codex processes running, exactly one app-server process, and exactly one refresh attempt, the newly issued refresh token was rejected with:
refresh_token_invalidated
The first isolated refresh returned no auth token, last_refresh did not update, and the refresh token did not rotate.
So signing out and signing back in does not resolve the issue.
What steps can reproduce the bug?
- Sign in to Codex Desktop using a ChatGPT Plus personal account.
- Confirm the account is initially authenticated and usable.
- Use the Desktop app normally or wait after startup.
- Desktop eventually sends:
GET /backend-api/accounts/{account_id}/settings
- The request returns HTTP 401 while the cached access token is still present.
- Desktop automatically forces an authentication refresh.
- The refresh path returns no auth token and the logs show:
auth_token_missing
- Desktop then returns to the "Log in to ChatGPT" screen.
- Without logging in again, read the existing access token from
~/.codex/auth.jsonand use it against:
GET https://chatgpt.com/backend-api/wham/usage
- The request still returns HTTP 200, demonstrating that the access token is valid while Desktop considers the account logged out.
I also reproduced the refresh-token failure independently:
- Fully close Desktop.
- Confirm zero ChatGPT/Codex processes are running.
- Perform a fresh official ChatGPT login using Codex.
- Confirm a newly issued refresh token exists.
- Start exactly one Codex app-server.
- Perform exactly one refresh request.
- The first refresh fails with:
refresh_token_invalidated
No second app-server or Desktop process is running during this isolation test.
What is the expected behavior?
For a ChatGPT Plus personal account:
- Desktop should not request workspace-only account settings unless the account actually supports that endpoint.
- If
/accounts/{account_id}/settingsreturns 401 because the endpoint is unavailable for a personal account, that error should be isolated to that feature/query and should not invalidate the entire ChatGPT session.
- A still-valid cached access token should not be discarded merely because an unrelated authenticated endpoint returned HTTP 401.
- If token refresh fails while the current access token is still valid, Desktop should continue using the valid access token instead of immediately transitioning to
auth_token_missing.
- A newly issued refresh token should be usable for its first legitimate refresh attempt.
- Desktop should remain signed in and usable instead of returning to the login screen.
Additional information
Additional diagnostics already performed:
- Account backend classification: Plus / personal
- Local app-server classification: Plus
- Existing access token remains valid after the UI logout (
/wham/usage= HTTP 200) - Fresh login does not resolve the problem
- Cross-process refresh race was ruled out with a strict single-process isolation test
- Proxy/network connectivity is working normally
- Recreating the local Codex state did not resolve the issue
- The problem reproduces with newly created Work sessions, so it is not specific to an old conversation
I can provide sanitized Desktop logs if needed.
For privacy/security, access tokens, refresh tokens, account IDs, user IDs, and email addresses have been omitted.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
我也一样
Additional data point that isolates this further: on my machine the failing refresh is not preceded by any 401 at all. The brand-new refresh token is rejected on its first ever use, with no triggering
/accounts/{account_id}/settingsfailure in the picture.Environment
26.820.7780.0(MSIX from the Store listing9PLM9XGG6VKS)app_server.client_version=26.820.60940, codex core0.150.0auth_mode = "chatgpt"), noOPENAI_API_KEYsetWhat I did
Full clean re-auth: killed the entire process tree (8
ChatGPT.exe+ 1codex.exe, verified 0 remaining), deleted%USERPROFILE%\.codex\auth.json, relaunched, signed in through the browser flow.The file was written correctly —
auth.jsonmtime updated,last_refreshset to the login time, and therefresh_tokensha256 differs from the previous one. So this is not a stale-file / failed-write problem.Timeline (single session, local time UTC+8)
| Time | Event |
|---|---|
| 14:21:34 |
codex_login::serverreceived login callback,state_valid=true|| 14:21:35 |
oauth token exchange succeeded status=200 OK;Reloaded auth, changed: true;auth.jsonwritten || 14:21:38 |
GET /backend-api/codex/models→ 200 || 14:21:38 |
POST /backend-api/ps/apps/batch→ 200 || 14:21:41 |
POST /backend-api/codex/analytics-events/events→ 200 || 14:21:47 |
GET /backend-api/codex/models→ 200 (auth_header_attached=true auth_mode="Chatgpt") || 14:22:09 | user opens an existing thread →
thread/resume|| 14:22:10 |
POST /backend-api/codex/analytics-events/events→ 200 ×2 || 14:22:11 |
getAuthStatus→POST https://auth.openai.com/oauth/token→ 401 |Lifetime of the brand-new refresh token: 36 seconds, on its first use.
That
oauth/token401 is the only non-2xx response and the only ERROR row in the entire session'slogs_2.sqlite. Every preceding request returned 200.The access token stays valid
The access token issued in the same exchange decodes to
exp= 10 days out (2026-09-05), and it was still being accepted with 200 twelve seconds before the refresh failed. So the app discards a working credential purely because the refresh path failed.Ruling out sibling clients
I saw #22903-style multi-client rotation suggested elsewhere, so I checked: enumerating
Win32_Processwith full command lines at the moment of failure showed exactly onecodex.exeapp-server (spawned by the desktop app itself), plus theChatGPT.exerenderer/GPU/utility children. Nothing else on the box held the Windows credential.I do have a Codex CLI running under WSL, but it is a completely separate
~/.codex/auth.jsonwith a different refresh token, it polls/modelsevery 3 minutes returning 200 OK continuously across the whole window (including at 14:21:46, 11s after the Windows login), and itsauth.jsonhas not been rewritten since it logged in the previous day — i.e. it never refreshes at all. It is unaffected before, during, and after the Windows failure.Notes on the suggested workarounds
Deleting
auth.jsonand re-authenticating does not help — that is exactly what produced the timeline above. The replacement token dies the same way, in well under a minute, on first use.I can reproduce the same failure on a newer current Microsoft Store build, and it also reproduces with two different ChatGPT accounts.
Environment
OpenAI.Codex 26.820.9563.0(Status: Ok)0.150.0-alpha.8(logs reportclient_version=0.150.0)0.150.1(continues to work)9PLM9XGG6VKSFresh isolated reproduction
Before the test I:
%USERPROFILE%\.codex\auth.jsonand its backup.%APPDATA%\Codex\web\CodexChromium profile.auth.openai.comandchatgpt.comhad the same public egress IP and Cloudflare colo.Relevant UTC timeline from the fresh run:
Immediately before the forced refresh, Desktop also logged:
The UI then returned to the login screen.
The standalone CLI was only started at
07:35:26, after Desktop had already receivedrefresh_token_invalidatedat07:35:08. Therefore a local Desktop/CLI refresh race was not present in this reproduction.The same behavior was reproduced with a second ChatGPT account on the same clean Desktop profile, so this does not appear to be specific to one account's token family.
Additional controls
This evidence is consistent with the issue's proposed failure chain: a non-session-specific 401 from the account settings request causes Desktop to force an immediate refresh, and the first refresh of a newly issued token is rejected, after which Desktop discards the otherwise fresh login state.
No tokens, account IDs, user IDs, email addresses, or public IP addresses are included here. I can provide a narrowly filtered and sanitized log excerpt if maintainers need it.