Repository navigation
Windows MCP OAuth keyring credentials are ignored on restart #28201
Description
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:
[mcp_servers.notion] type = "http" url = "https://mcp.notion.com/mcp"
-
Use default MCP OAuth credential storage (
auto) or explicitly set:mcp_oauth_credentials_store = "keyring"
-
Run:
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: OAuth tokens too long for Windows keyring #10353
- Related PR: fix: support encrypted local secrets for keyring auth #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:
- Unable to connect to certain MCPs, including the Mobbin MCP #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. - Codex Desktop does not refresh OAuth-backed MCP access token before startup; keeps sending expired bearer from Keychain #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.
Activity
github-actions commentedon Jun 14, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Q1Xuan commentedon Jun 14, 2026
Reviewed the suggested duplicates.
.credentials.jsoncredentials not being attached/read during MCP startup. This issue is specifically about Windows keyring-backed storage, where a legacy direct Windows Credential Manager entry (Codex MCP Credentials/server|hash) exists but the newer encrypted secrets backend does not read it.I updated the issue body with this comparison and cleaned up the Markdown formatting. I think #28201 should stay open as a narrower compatibility/migration bug unless maintainers prefer folding it into one of those broader MCP OAuth startup issues.
Q1Xuan commentedon Jun 15, 2026
Local validation update for the proposed minimal fix on
Q1Xuan:fix/windows-mcp-oauth-keyring-migration(b9c9820):cargo-nextest 0.9.137from the official Windows MSVC release asset and verified its SHA-256.just fmtfromcodex-rs: passed.just fix -p codex-rmcp-client: passed.cargo build -p codex-cli --bin codex: passed. I built this first so thecodex-rmcp-clientintegration test that spawnstarget/debug/codex.execan run locally on Windows.just test -p codex-rmcp-client: passed, 84 passed / 2 skipped.I did not run full
just test: this patch is scoped tocodex-rs/rmcp-client/src/oauth.rsand does not touch common/core/protocol. The targeted crate checks now pass locally.Per
docs/contributing.md, I am not opening a PR unless a Codex maintainer explicitly invites one.alisterwayne8-web commentedon Sep 21, 2026
Additional confirmation from an n8n MCP setup on Windows:
Using
mcp_oauth_credentials_store = "file"resolved the OAuth persistence problem for Codex Desktop after re-running:The working config also included the n8n-generated RMCP flag:
After verifying
codex mcp listshowedn8n -> enabled -> OAuth, fully quitting Codex Desktop and starting a new thread allowed Desktop to successfully call the remote n8n MCP tools.I documented the full Windows + n8n workaround on #32220 as well.