ChatGPT desktop 0.147 removes the OAuth issuer required by CLI 0.149+
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of Codex CLI is running?
Standalone CLI: 0.151.0
Codex bundled with ChatGPT desktop: 0.147.0-alpha.6.5
ChatGPT desktop: 26.803.61601
What subscription do you have?
The standalone CLI uses API key authentication. This failure is in MCP OAuth and occurs before model use.
Which model were you using?
N/A. The failure occurs during MCP startup.
What platform is your computer?
Darwin 25.6.0 arm64 arm
What terminal emulator and version are you using (if applicable)?
Ghostty 1.3.1. ChatGPT desktop was running on the same Mac.
Codex doctor report
The full report contains local paths and private MCP endpoints. These are the relevant fields:
{
"codexVersion": "0.151.0",
"desktop": {
"running": true,
"version": "26.803.61601",
"embeddedCodexVersion": "0.147.0-alpha.6.5"
},
"installation": {
"status": "ok",
"installMethod": "npm",
"version": "0.151.0"
},
"platform": "macos-aarch64"
}
What issue are you seeing?
ChatGPT desktop and the standalone CLI share MCP OAuth credentials in macOS Keychain, but their Codex versions update independently. The older desktop client can refresh a credential written by the newer CLI and remove the issuer field. When the access token later expires, Codex 0.149 or newer refuses to use the refresh token and requires another browser login.
I observed this twice in two days across two remote Streamable HTTP MCP servers. The sequence was the same for both servers:
-
codex mcp login <server>on the current CLI completed successfully. The stored credential includedissuer. -
ChatGPT desktop later refreshed the credential and persisted it through the shared Keychain entry. The resulting record no longer included
issuer. -
After the access token expired, CLI 0.151.0 loaded the record and fetched the OAuth metadata. It did not call the token endpoint.
-
Startup reported:
The <server> MCP server requires OAuth reauthentication. Run `codex mcp login <server>`. -
Running
codex mcp login <server>again restored the connection until the older desktop client refreshed the credential again.
Provider logs confirm that the failed CLI startup did not send a refresh request. This rules out a provider-side refresh-token rejection for these occurrences. The server names, URLs and provider logs are private, so they are omitted here.
What steps can reproduce the bug?
- On macOS, configure a remote OAuth MCP server with short-lived access tokens and refresh tokens.
- Use a standalone Codex version that includes #39615, such as 0.149.0 or newer.
- Use ChatGPT desktop with bundled Codex 0.147.0 on the same account and
CODEX_HOME, with the default Keychain credential store. - Authenticate the MCP server from the standalone CLI. Confirm that the stored credential includes
issuerwithout printing the credential values. - Let the access token expire, then allow the desktop client to refresh it and persist the result.
- Confirm that the shared credential no longer includes
issuer. - After the refreshed access token expires, start the newer standalone CLI.
The newer CLI reports that reauthentication is required before it sends a request to the token endpoint.
What is the expected behavior?
An older desktop client must not make credentials written by a newer CLI unusable. Codex surfaces that share a credential store need a backward-compatible storage contract across independent releases.
The current CLI should continue to reject a refresh token that cannot be bound to its issuer. Possible fixes include preserving unknown credential fields during writes, versioning the Keychain record or preventing an older client from replacing a newer credential schema. Updating the desktop bundle before the newer schema reaches the standalone CLI would also prevent this version combination.
Additional information
#39615 added issuer to StoredOAuthTokens and requires reauthentication when an expired credential has a refresh token but no issuer. Codex 0.147.0 predates that field. Its refresh path serializes the full StoredOAuthTokens value, so it drops an issuer value written by a newer client.
Related issues:
- #33540 covers concurrent refresh persistence in a shared Keychain. This report covers a different failure: a successful refresh by an older client downgrades the credential schema.
- #35006 tracks the broader MCP OAuth lifecycle across CLI, desktop and IDE surfaces. It states that the surfaces should not overwrite shared credentials, but it does not include this version-skew reproduction.
The local source checks were against rust-v0.147.0, #39615 and rust-v0.151.0. Reauthentication replaced the affected Keychain record, so I cannot attach the original record. The provider request timeline and the cross-version serialization behavior support the diagnosis.
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 by reading the StoredOAuthTokens change in #39615 and the refresh-path serialization in rust-v0.147.0, then compare it with rust-v0.151.0 using the shared macOS Keychain flow described here. Reproduce the version-skew sequence with an expiring OAuth MCP credential; done means an older client refresh no longer removes issuer, while the newer CLI retains its issuer validation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- authentication, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100