MCP OAuth refresh omits the RFC 8707 resource parameter and breaks authenticated servers after access-token expiry
What version of the Codex App are you using (From “About Codex” dialog)?
Codex App 26.707.72221 (build 5307), bundled codex-cli 0.144.2
What subscription do you have?
ChatGPT Pro
What platform is your computer?
Darwin 25.5.0 arm64 arm
What issue are you seeing?
A remote Streamable HTTP MCP server authenticates and works immediately after OAuth login, but stops working when the 15-minute access token expires.
The authorization server requires the RFC 8707 resource parameter in authorization and token requests, as required by the MCP 2025-11-25 authorization specification.
In Codex App 26.707.72221, after token expiry the MCP server becomes unavailable and a required MCP server can prevent creation of a new task:
Failed to initialize session: required MCP servers failed to initialize: supportpal: handshaking with MCP server failed: Send message error Transport [rmcp::transport::worker::WorkerTransport<rmcp::transport::streamable_http_client::StreamableHttpClientWorker<rmcp::transport::auth::AuthClient<codex_rmcp_client::http_client_adapter::StreamableHttpClientAdapter>>>] error: Auth error: OAuth authorization required, when send initialize request
Server-side audit showed that the access token had expired, while the rotating refresh token remained valid. With the bundled CLI 0.144.2, no successful refresh reached the token endpoint.
I repeated the test using codex-cli 0.144.3. That version attempted refresh, but omitted resource and failed with:
Token refresh not possible, re-authorization required: OAuth token refresh failed: Server returned error response: invalid_target: resource is required and must match this MCP server.
The project configuration already supplies the canonical resource:
[mcp_servers.supportpal]
url = "https://support.yourdomain.com/mcp"
oauth_resource = "https://support.yourdomain.com/mcp"
required = true
[mcp_servers.supportpal.oauth]
client_id = "codex-desktop-support-yourdomain"
The configured oauth_resource is present during login but is not included in the refresh-token request.
What steps can reproduce the bug?
- Configure a Streamable HTTP MCP server whose OAuth token endpoint requires
resourceon every token request:
[mcp_servers.supportpal]
url = "https://support.yourdomain.com/mcp"
oauth_resource = "https://support.yourdomain.com/mcp"
required = true
[mcp_servers.supportpal.oauth]
client_id = "codex-desktop-support-yourdomain"
- Authenticate the MCP server through Codex App.
- Start a task and confirm that MCP initialization and a metadata-only tool call succeed.
- Wait until the access token expires. The test server uses a 15-minute access-token TTL and a 30-day rotating refresh-token TTL.
- Start another task or invoke the MCP server again.
- Observe that Codex App cannot restore the MCP connection. With codex-cli 0.144.3, the refresh request is sent without resource and the authorization server returns:
invalid_target: resource is required and must match this MCP server.
Investigation session ID:
019f5c1e-7426-7a42-bcbe-c1017fef84ef
The 0.144.3 command-line reproduction used codex exec --ephemeral. thread/start failed during required MCP initialization, before a persistent session ID was created.
Token-limit and context-window usage are not applicable; the failure happens during MCP initialization before the task starts.
What is the expected behavior?
Codex should include the configured canonical resource in every OAuth token request, including refresh-token requests:
resource=https://support.yourdomain.com/mcp
When the access token expires, Codex should use the still-valid refresh token, accept and persist the rotated refresh token, and continue using the MCP server without requiring another browser authorization.
A required MCP server should not prevent task creation when a valid refresh token can be refreshed successfully.
Additional information
The MCP specification requires clients to include resource in both authorization and token requests:
This exact omission was fixed upstream in the MCP Rust SDK on July 3, 2026:
https://github.com/modelcontextprotocol/rust-sdk/pull/951
The PR states:
Refresh-token requests omitted the RFC 8707 resource parameter, which the spec requires on all token requests.
Codex 0.144.3 still pins rmcp 1.8.0, whose refresh path does not contain that fix. The Codex 0.144.3 release is documented as a version-only release with no merged changes since 0.144.2:
https://github.com/openai/codex/releases/tag/rust-v0.144.3
Codex previously added oauth_resource handling for MCP login flows in:
https://github.com/openai/codex/pull/12866
That change covered the authorization/login path, but not refresh-token requests.
Suggested fix: update the rmcp dependency to a revision containing modelcontextprotocol/rust-sdk#951, or cherry-pick the equivalent change so the refresh request includes the configured oauth_resource.
The MCP server should not be changed to accept refresh requests without resource, because doing so would weaken token audience binding. Setting required = false prevents the entire Codex task from failing, but it does not restore MCP access and is only an availability workaround.
7 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
i have the same issue
Confirmed this on Codex 0.145.0 with the same MCP server on both macOS and Linux.
At access-token expiry:
401 AuthRequired.The initial authorization-code exchange produces the correct audience, so the failure is specific to refresh. This matches RMCP 1.8.0 omitting
resourcefromexchange_refresh_token().Updating RMCP to a version containing modelcontextprotocol/rust-sdk#951—or cherry-picking that refresh-path change—should fix this.
rmcpwas upgraded from 1.8.0 to 3.0.0 in https://github.com/openai/codex/pull/35720 and https://github.com/openai/codex/pull/36001. This means this issue should be fixed in the latest Codex's alpha releases rust-v0.146.0-alpha.15, rust-v0.147.0-alpha.1 or newer. Likely it is resolved, but I haven't run the alpha release to confirm.EDIT: on
v0.147.0-alpha.4this issue seems to be resolved and it auto-refreshed OAuth sessions for me. However, due to it being more strict, one of the MCPs I'm gettingError: Authorization server issuer mismatch: expected https://auth.example.com/..., received https://auth.example.comwhen doingcodex mcp login example.https://auth.example.com/...as its issuer but returnshttps://auth.example.comin the corresponding authorization-server metadata.rmcp 3.0dependency strictly rejects that mismatch, while codex with the olderrmcp 1.8tolerated it.adding resource to the refresh request is the right call, but there is a second quiet failure sitting behind it. with a rotating refresh token, a successful refresh hands you a NEW refresh token, and if you persist the fresh access token but the rotated refresh token does not land (write races the task exit, partial flush, whatever), the next expiry replays reauthorization required against an already-consumed token. that surfaces as plain session-expired, so you cant tell a real 30-day expiry apart from a dropped rotation. worth asserting the rotated token actually persisted before you treat the refresh as succeeded, otherwise the fix just moves the silent break one cycle downstream.
Still reproducible in Codex desktop 0.146.0-alpha.9.2 (embedding rmcp 1.8.0). Initial OAuth authorization succeeds against a resource-bound MCP server. After the one-hour access token expires, Codex attempts refresh, but the refresh request omits the RFC 8707 resource parameter. The server rejects it with invalid_grant; manual reauthentication works until the next access-token expiry. Please update rmcp to the version containing the refresh-resource fix.
Still reproducible with a newer Codex build that already embeds
rmcp 3.0.0.Environment
26.810.41047(build6570)codex-cli 0.148.0-alpha.926.6.1(25G76), Apple Siliconhttps://mcp.apify.comClean reproduction
https://mcp.apify.com.codex mcp login apifyand completed OAuth.The issued refresh token advertised an approximately 60-day lifetime. Its stored credential was written only at login and was not modified before the failed refresh, ruling out an earlier successful rotation followed by stale-token replay. No competing Codex process existed during the reproduction.
Likely root cause
rmcp 3.0.0contains a second refresh-resource bug after the earlier missing-resource fix.Initial authorization and authorization-code exchange use the resource discovered from RFC 9728 protected-resource metadata:
But the
rmcp 3.0.0refresh path uses:Apify’s protected-resource metadata identifies the canonical resource as:
The refresh path can therefore send a different serialized audience, such as:
This exactly matches the upstream bug fixed by modelcontextprotocol/rust-sdk#1084:
https://github.com/modelcontextprotocol/rust-sdk/pull/1084
That fix shipped in
rmcp 3.0.1:https://github.com/modelcontextprotocol/rust-sdk/releases/tag/rmcp-v3.0.1
Codex currently pins
rmcpexactly to3.0.0, includingrust-v0.148.0-alpha.15, so upgrading between current 0.148 alpha builds does not include the upstream fix:https://github.com/openai/codex/blob/rust-v0.148.0-alpha.15/codex-rs/Cargo.toml#L399
Suggested fix
Update Codex from
rmcp = "=3.0.0"tormcp >= 3.0.1, or cherry-pick the one-line upstream fix so refresh usesself.oauth_resource().await.A regression test should cover a root MCP endpoint whose protected-resource metadata omits the trailing slash and confirm that authorization, code exchange, and refresh all send the identical discovered resource.
No token or credential values are included in this report.