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
Nobody has claimed this yet.
- 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.
-
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.
-
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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