MCP OAuth: Codex does not re-register (DCR) on invalid_client / expired refresh token — requires manual re-auth
Summary
When an MCP server's refresh token is rotated or expired, Codex logs Token refresh not possible, re-authorization required and stops. It does not discard the dead client_id and POST to the advertised registration_endpoint to re-register, as OAuth 2.1 / the MCP Dynamic Client Registration (DCR) spec expect. Users must manually log out and re-add the server to recover.
Evidence
From ~/.codex/logs_2.sqlite (target rmcp::transport::auth):
Access token expired or nearly expired, refreshing. remaining_secs=0
refresh token present, attempting refresh
Token refresh not possible, re-authorization required.
error=OAuth token refresh failed: Server returned error response: invalid_grant: refresh token ...
After this point there is no subsequent /register call — the flow just halts. Over the lifetime of this install: 0 events handling invalid_client, only 3 /register events total.
Tested against a spec-compliant FastMCP OAuthProxy server that, for an unknown/stale client_id, returns:
POST /token→401 {"error":"invalid_client"}GET/POST /authorize→400 {"error":"invalid_request","error_description":"Client ID '...' is not registered with this server. MCP clients should automatically re-register by sending a POST request to the registration_endpoint and retry authorization...","registration_endpoint":"https://.../register"}
The server explicitly advertises the registration_endpoint and instructs the client to re-register. Codex ignores it.
Environment: Codex CLI 0.142.0 (macOS, compiled Rust binary). MCP OAuth credentials stored in macOS Keychain under service Codex MCP Credentials.
Impact
Any MCP server that rotates refresh tokens or restarts (losing server-side token state) logs every user out until they manually re-authenticate. codex mcp logout is an unreliable workaround — it is per-server/per-URL-hash scoped and has known cleanup gaps (#25002, #28201).
Expected behavior
On invalid_client (or an unrecoverable refresh failure), Codex should automatically discard the stored client_id + tokens, re-run dynamic client registration against the server's advertised registration_endpoint, and retry authorization — per the MCP authorization spec — rather than stopping and requiring manual intervention.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗