openai / openai/codex

ChatGPT Desktop 26.818.41705: valid OAuth token rejected with 401 "Missing valid access token or actor biscuit" on every session, started immediately after auto-update

Open
#40,143 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app auth bug
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.41705

What subscription do you have?

Pro x20

What platform is your computer?

Darwin 25.6.0 arm64 arm

What issue are you seeing?

After the Sparkle auto-update to ChatGPT Desktop 26.818.41705 (build 6971), every Desktop session loses ChatGPT authentication. A freshly minted, unexpired OAuth token is rejected by chatgpt.com/backend-api with 401, the Desktop then discards its own token cache, and the app drops to a signed-out state. The same account works normally in the browser and in the iOS/Android apps at the same moment, from the same machine and network.

Environment

macOS 26.6.2 (25G83), Apple silicon (Mac17,8)
ChatGPT Desktop 26.818.41705 (build 6971), bundle ID com.openai.codex
Bundled app-server 0.149.0-alpha.4.1
ChatGPT managed OAuth, auth_mode: chatgpt, plan pro
Single install in /Applications/ChatGPT.app, signature and embedded.provisionprofile intact
Migrated from the legacy ChatGPT app — every launch logs [legacy-chatgpt-sparkle-updater] Finished disarming legacy ChatGPT Sparkle updater cache=cleared

Failure signature (identical in every session; this instance is app session f5a88e01-3b3e-4866-9b2a-00aa2501666d, all times UTC)

19:01:46.965  info    [electron-message-handler] account_login_completed success=true
19:01:47.846  info    [chatgpt-account-lookup] completed authenticatedAccountPresent=true authMethod=chatgpt
              ... 63 seconds of normal operation ...
19:02:51.517  info    [devicecheck-attestation] DeviceCheck attestation generated
                      deviceCheckLatencyMs=17.49 durationMs=17
19:02:51.640  warning [electron-fetch-wrapper] desktop_fetch_auth_401 hadToken=true skipRetryReason=null
                      target="GET https://chatgpt.com/backend-api/accounts/{account_id}/settings"
                      tokenSource=cached willRetry=true
19:02:51.927  warning [AppServerConnection] app_server_connection.auth_status_result authMethod=chatgpt
                      cacheWrite=null hasToken=false nullReason=auth_token_missing
                      refreshToken=true tokenExpiryState=missing
19:02:51.953  info    [chatgpt-account-lookup] completed authenticatedAccountPresent=false
                      failureType=account_info_token_unavailable
19:02:52.088  warning [electron-message-handler] sa_server_request_failed attachAuth=true attachIntegrityState=true
                      errorMessage="{\"detail\":\"Missing valid access token or actor biscuit\"}"
                      routePattern=/accounts/{account_id}/settings status=401
19:02:52.153  warning [electron-fetch-wrapper] desktop_fetch_auth_401 hadToken=false
                      skipRetryReason=no_token_attached willRetry=false

The first failing call carries a token (hadToken=true). Every call after it carries none (hadToken=false, no_token_attached) because the Desktop invalidates its own token cache in response to the 401.

Endpoints returning 401

GET /backend-api/accounts/{account_id}/settings
GET /backend-api/accounts/check/{version}
GET /backend-api/wham/tasks/list
GET /backend-api/wham/usage
GET /backend-api/wham/onboarding/context
GET /backend-api/payments/payment_methods
GET /backend-api/ps/plugins/home
GET /backend-api/ps/plugin-categories/{category_slug}/plugins

Both error bodies observed:

json
{"detail":"Missing valid access token or actor biscuit"}
{"detail":"Unauthorized"}

The bundled Rust app-server hits the same wall independently of the Electron shell, so this is not specific to one transport:

remote_connections.manager_state_set nextError={"code":"connection-failed","message":
  "failed to warm featured plugin ids cache",
  "error":"remote featured plugin request to
   https://chatgpt.com/backend-api/plugins/featured?platform=codex
   failed with status 401 Unauthorized: {\"detail\":\"Unauthorized\"}"}

The token being rejected is valid. Decoded from ~/.codex/auth.json right after a successful account_login_completed, while the Desktop was already reporting auth_token_missing:

auth_mode     : chatgpt
last_refresh  : 2026-08-22T18:48:55Z      (8 seconds before the 401)
access_token  : iat 2026-08-22T18:48:54Z
                exp 2026-09-01T18:48:54Z   -> NOT expired, 10 days remaining
                iss https://auth.openai.com
                aud ["https://api.openai.com/v1"]
                scp [openid, profile, email, offline_access,
                     api.connectors.read, api.connectors.invoke]
claim https://api.openai.com/auth:
  chatgpt_account_id : <matches the {account_id} in the failing request path>
  chatgpt_plan_type  : pro
  amr                : [google, otp, mfa, otp_email, pop, passkey]

account_id in auth.json == chatgpt_account_id in the JWT == {account_id} in the URL that returns 401. tokenExpiryState=missing is reported against a token that is present and has 10 days of validity left.

What steps can reproduce the bug?

Reproduces on 26 of 26 launches on this machine. No code snippet applies — this is the packaged Desktop app with a stock configuration.

Launch ChatGPT Desktop 26.818.41705 on macOS 26.6.2, signed in with ChatGPT managed OAuth.
Use the app normally — open any thread, or leave it idle.
Within 8 seconds to 34 minutes, the app issues GET /backend-api/accounts/{account_id}/settings, receives 401, and drops to a signed-out state.
Sign in again. account_login_completed success=true, a new valid token is written to ~/.codex/auth.json, and the cycle repeats — the fastest observed recurrence was 7 seconds after a successful login.

Session IDs (app session, from ~/Library/Logs/com.openai.codex/2026/08/22/):

f5a88e01-3b3e-4866-9b2a-00aa2501666d   launch 19:01:36Z   first 401 19:02:51Z   (+75s)
f9f2e632-8b7a-4c05-8302-e71cbf64695e   launch 18:55:16Z   first 401 18:55:33Z   (+17s)
320b693d-b0…                           launch 18:48:46Z   first 401 18:49:03Z   (+17s)
fdb9926e-8d3c-4f0c-afd6-f17b7a1ac6fd   launch 18:36:24Z   first 401 18:36:34Z   (+10s)
c9fe28ae-1d3a-40b1-8501-eface6fec0ef   launch 12:38:10Z   first 401 13:11:54Z   (+2024s)

Token limit / context window usage is not applicable — the failure is in the account/settings control-plane call, and it occurs on idle sessions with no turn in flight.

Not required to reproduce: any particular thread. It fails on 232 MB, 35 MB and 11 MB rollouts, on brand-new threads, and in 3 sessions where no thread was ever resumed.

What is the expected behavior?

Two separate things.

  1. The token should be accepted. A freshly minted, unexpired access token whose chatgpt_account_id matches the requested account, sent from an app whose DeviceCheck attestation succeeded ~120 ms earlier, should be accepted by chatgpt.com/backend-api. If it is genuinely invalid, the 401 should say which of the two credentials failed and why — Missing valid access token or actor biscuit names both and distinguishes neither, which makes it impossible to tell a token problem from an attestation or biscuit-minting problem.

  2. A single 401 should not sign the user out. On receiving 401, the Desktop currently discards its stored token and downgrades every subsequent request to hadToken=false / no_token_attached. One rejected control-plane call becomes a full sign-out, and the stored token — still valid for 10 days — is never retried. Expected: the Desktop retains a token that has not expired, retries or refreshes, and surfaces a specific error instead of silently degrading to a signed-out state.

Additional information

No response

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 with the bundled Rust app-server and the Electron authentication logs, then compare the failing endpoints with ~/.codex/auth.json and the recorded session traces. Reproduce the 401 cycle on ChatGPT Desktop 26.818.41705; done means valid sessions no longer incorrectly lose authentication, and failures identify the rejected credential clearly.

Written by the indexing model from the issue text.

Assessment

Tech stack
electron, macos, rust
Domain
api, authentication, desktop
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.