openai / openai/codex

Windows Desktop: fresh ChatGPT refresh token is rejected as refresh_token_invalidated on its first isolated refresh, causing false logout after unrelated 401

Open
#39,925 4 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app app-server auth bug windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

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/check returns HTTP 200
  • plan_type = plus
  • structure = personal
  • local Codex app-server account/read returns planType = plus

The reproducible failure chain in the Desktop logs is:

  1. Desktop starts in a valid authenticated state:
    authenticatedAccountPresent=true

  2. Desktop sends:
    GET /backend-api/accounts/{account_id}/settings

  3. That request returns HTTP 401 while:
    hadToken=true
    tokenSource=cached

  4. The generic auth wrapper treats the 401 as an authentication failure and forces:
    refreshToken=true

  5. The refresh fails and app-server reports:
    authMethod=chatgpt
    hasToken=false
    nullReason=auth_token_missing

  6. Account lookup then becomes:
    authenticatedAccountPresent=false
    failureType=account_info_token_unavailable

  7. 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?
  1. Sign in to Codex Desktop using a ChatGPT Plus personal account.

  2. Confirm the account is initially authenticated and usable.

  3. Use the Desktop app normally or wait after startup.

  4. Desktop eventually sends:
    GET /backend-api/accounts/{account_id}/settings

  5. The request returns HTTP 401 while the cached access token is still present.

  6. Desktop automatically forces an authentication refresh.

  7. The refresh path returns no auth token and the logs show:
    auth_token_missing

  8. Desktop then returns to the "Log in to ChatGPT" screen.

  9. Without logging in again, read the existing access token from ~/.codex/auth.json and use it against:
    GET https://chatgpt.com/backend-api/wham/usage

  10. 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:

  1. Fully close Desktop.
  2. Confirm zero ChatGPT/Codex processes are running.
  3. Perform a fresh official ChatGPT login using Codex.
  4. Confirm a newly issued refresh token exists.
  5. Start exactly one Codex app-server.
  6. Perform exactly one refresh request.
  7. 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:

  1. Desktop should not request workspace-only account settings unless the account actually supports that endpoint.

  2. If /accounts/{account_id}/settings returns 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.

  3. A still-valid cached access token should not be discarded merely because an unrelated authenticated endpoint returned HTTP 401.

  4. 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.

  5. A newly issued refresh token should be usable for its first legitimate refresh attempt.

  6. 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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the generic auth wrapper around GET /backend-api/accounts/{account_id}/settings and the app-server refresh path, using the Desktop logs and ~/.codex/auth.json behavior described here. Reproduce the isolated refresh failure and the still-valid /backend-api/wham/usage token, then verify that a personal account remains signed in when the settings request or refresh fails.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, authentication, desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.