Windows MCP OAuth keyring credentials are ignored on restart
What version of Codex CLI is running?
codex-cli 0.139.0
What subscription do you have?
Unknown / not relevant to local MCP OAuth persistence.
Which model were you using?
gpt-5.5 via a custom Responses-compatible provider.
What platform is your computer?
Microsoft Windows NT 10.0.19045.0 x64
What terminal emulator and version are you using (if applicable)?
Windows Terminal / PowerShell.
Codex doctor report
Captured after applying the temporary workaround (mcp_oauth_credentials_store = "file"), so it no longer reflects the failing keyring-mode startup. Relevant details:
codexVersion: 0.139.0
platform: windows-x86_64
install method: npm
mcp configured servers: 1 streamable_http server
config loaded from: C:\Users\Administrator\.codex\config.toml
current workaround: mcp_oauth_credentials_store = "file"
What issue are you seeing?
On Windows with a streamable HTTP MCP server using OAuth (Notion MCP), Codex CLI can complete codex mcp login notion, and Windows Credential Manager may contain a legacy direct keyring entry named like notion|... under service Codex MCP Credentials. However, a fresh Codex startup still fails MCP initialization with:
MCP client for `notion` failed to start
OAuth authorization required, when send initialize request
MCP startup incomplete (failed: notion)
Running codex mcp logout notion && codex mcp login notion does not reliably make keyring-mode persistence usable on later startups. Setting this workaround in config.toml and logging in again fixes startup:
mcp_oauth_credentials_store = "file"
That workaround creates $CODEX_HOME/.credentials.json, which avoids the startup failure but stores OAuth tokens in a plaintext file readable by Codex and other same-user processes. The preferred long-term behavior is for the default/keyring path to persist and reload MCP OAuth credentials reliably on Windows.
What steps can reproduce the bug?
- On Windows, configure Notion MCP as a streamable HTTP server:
``toml``
[mcp_servers.notion]
type = "http"
url = "https://mcp.notion.com/mcp"
- Use default MCP OAuth credential storage (
auto) or explicitly set:
``toml``
mcp_oauth_credentials_store = "keyring"
- Run:
``powershell``
codex mcp logout notion
codex mcp login notion
- Complete OAuth in the browser.
- Confirm
codex mcp listshows Notion as enabled with OAuth. - Start a fresh Codex CLI process.
Observed result: Codex startup reports OAuth authorization required for the Notion MCP server even though OAuth login completed and a Windows Credential Manager entry may exist.
What is the expected behavior?
After a successful MCP OAuth login, a fresh Codex CLI process should read the persisted OAuth credentials from the Windows keyring-backed store and initialize the Notion MCP server without prompting for OAuth again.
The default auto mode should not require falling back to plaintext $CODEX_HOME/.credentials.json for stable persistence.
Additional information
I investigated current main and found a likely compatibility gap in the keyring backend transition introduced to avoid Windows Credential Manager payload size limits:
- Related issue: https://github.com/openai/codex/issues/10353
- Related PR: https://github.com/openai/codex/pull/17931
In current source, AuthKeyringBackendKind::Secrets reads MCP OAuth credentials from encrypted local secrets. If no encrypted MCP OAuth secret exists, it returns None and does not attempt to read the legacy direct keyring entry (Codex MCP Credentials / server|hash). Existing direct entries are therefore invisible after the secrets backend is selected.
I prepared a small patch that makes the secrets backend fall back to the legacy direct keyring entry when the encrypted MCP OAuth store has no token, then best-effort migrates it into encrypted storage and removes the old direct entry.
Prepared branch:
https://github.com/Q1Xuan/codex/tree/fix/windows-mcp-oauth-keyring-migration
Local patch:
C:\Users\Administrator\codex-mcp-oauth-keyring-migration.patch
Validation performed locally:
rustfmt --edition 2024 --config imports_granularity=Item rmcp-client/src/oauth.rs
git diff --check -- codex-rs/rmcp-client/src/oauth.rs
I could not complete the targeted cargo test -p codex-rmcp-client ... locally because this checkout is a partial/sparse clone and additional workspace object fetches from GitHub repeatedly failed with TLS EOF errors.
Per docs/contributing.md, external code contributions are invitation-only, so I am opening this issue first with reproduction details, root-cause analysis, and the proposed fix branch rather than submitting an unsolicited PR.
Duplicate review
I reviewed the auto-suggested related issues:
- #27799: similar MCP startup symptom, but that report says a token in
.credentials.jsonworks when used directly and Codex appears not to attach/read the file-backed token. This issue is specifically about Windows keyring-backed storage and legacy direct keyring entries being ignored after the encrypted secrets backend is selected. - #27165: related OAuth-backed MCP startup failure, but the reported root cause is expired access tokens not being refreshed before startup/tool discovery. This issue is about valid persisted credentials not being found because they are in the older direct keyring location.
So this appears related, but not an exact duplicate.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗