Windows MCP OAuth keyring credentials are ignored on restart

Open 💬 3 comments Opened Jun 14, 2026 by Q1Xuan
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

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?

  1. On Windows, configure Notion MCP as a streamable HTTP server:

``toml
[mcp_servers.notion]
type = "http"
url = "https://mcp.notion.com/mcp"
``

  1. Use default MCP OAuth credential storage (auto) or explicitly set:

``toml
mcp_oauth_credentials_store = "keyring"
``

  1. Run:

``powershell
codex mcp logout notion
codex mcp login notion
``

  1. Complete OAuth in the browser.
  2. Confirm codex mcp list shows Notion as enabled with OAuth.
  3. 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:

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.json works 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.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 2 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #27799
  • #27165

Powered by Codex Action

Q1Xuan · 2 months ago

Reviewed the suggested duplicates.

  • #27799 is related by symptom, but it appears to involve file-backed .credentials.json credentials 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.
  • #27165 is also related, but it is about expired access tokens not being refreshed before startup/tool discovery. This issue is about persisted credentials not being found at all after the direct-keyring-to-secrets backend transition.

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 · 2 months ago

Local validation update for the proposed minimal fix on Q1Xuan:fix/windows-mcp-oauth-keyring-migration (b9c9820):

  • Installed cargo-nextest 0.9.137 from the official Windows MSVC release asset and verified its SHA-256.
  • just fmt from codex-rs: passed.
  • just fix -p codex-rmcp-client: passed.
  • cargo build -p codex-cli --bin codex: passed. I built this first so the codex-rmcp-client integration test that spawns target/debug/codex.exe can 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 to codex-rs/rmcp-client/src/oauth.rs and 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.