MCP OAuth with Microsoft Entra fails when protected-resource metadata has a no-trailing-slash resource

Resolved 💬 0 comments Opened Jul 28, 2026 by hhoangdo Closed Jul 28, 2026

Summary

codex mcp login cannot authenticate against the Microsoft Fabric Core MCP server because the emitted Microsoft Entra authorization URL sends a resource parameter with a trailing slash, while the requested Fabric scope identifies the same resource without one. Microsoft Entra rejects the request before the user can grant consent:

AADSTS9010010: The resource parameter provided in the request doesn't match with the requested scopes.

This is distinct from #17265, #13891, and #33403. Those reports concern missing/omitted resource or scope propagation; this report concerns an extra trailing slash in an emitted resource value.

Environment

  • Codex CLI: 0.145.0
  • OS: Windows
  • MCP server: https://api.fabric.microsoft.com/v1/mcp/core
  • OAuth client: pre-registered Microsoft Entra public client with PKCE
  • Codex callback: configured local localhost callback (registered successfully)
  • No bearer token, client secret, certificate, service principal, or proxy

Fabric OAuth protected-resource metadata

{
  "issuer": "https://login.microsoftonline.com/organizations/v2.0",
  "authorization_servers": [
    "https://login.microsoftonline.com/organizations/v2.0"
  ],
  "resource": "https://api.fabric.microsoft.com",
  "scopes_supported": [
    "https://api.fabric.microsoft.com/.default"
  ]
}

The resource is deliberately advertised without a trailing slash.

Codex configuration

mcp_oauth_callback_port = 19877
mcp_oauth_callback_url = "http://localhost:19877/codex-mcp"

[mcp_servers.fabric-core]
url = "https://api.fabric.microsoft.com/v1/mcp/core"
scopes = ["https://api.fabric.microsoft.com/.default"]
enabled = true

[mcp_servers.fabric-core.oauth]
client_id = "<redacted-public-client-id>"

There is no oauth_resource configuration.

Reproduction

  1. Run codex mcp login fabric-core.
  2. Inspect the authorization URL printed by Codex.
  3. It contains the following effective values (state, PKCE challenge, client ID, and redirect URI redacted):
scope=https://api.fabric.microsoft.com/.default
resource=https://api.fabric.microsoft.com/
  1. Microsoft Entra immediately returns AADSTS9010010.

Expected behavior

Codex must preserve the canonical protected-resource value from metadata and emit exactly one resource parameter:

scope=https://api.fabric.microsoft.com/.default
resource=https://api.fabric.microsoft.com

No trailing slash should be introduced.

The MCP authorization specification recommends a no-trailing-slash canonical resource form when the slash is not semantically significant:
https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization

Microsoft Fabric documents the same .default scope:
https://learn.microsoft.com/en-us/rest/api/fabric/articles/mcp-servers/core-remote/get-started-core

Suspected implementation area

In rust-v0.145.0, perform_oauth_login.rs delegates authorization URL construction to rmcp::AuthorizationManager; the subsequent Codex helper only appends an explicit oauth_resource value rather than replacing an existing query value:
https://github.com/openai/codex/blob/rust-v0.145.0/codex-rs/rmcp-client/src/perform_oauth_login.rs

This suggests the protected-resource URI is parsed/serialized as a URL and normalized to https://api.fabric.microsoft.com/, while the advertised scope remains https://api.fabric.microsoft.com/.default.

Requested fix

  1. Preserve the raw resource value returned by protected-resource metadata, including its trailing-slash semantics.
  2. Ensure the authorization URL contains exactly one resource parameter.
  3. If oauth_resource is configured, replace any existing resource parameter instead of appending another one.
  4. Forward the same exact resource value in authorization, token exchange, and refresh-token requests.
  5. Add a regression test with:
  • metadata resource: https://api.fabric.microsoft.com
  • scope: https://api.fabric.microsoft.com/.default
  • assertion: exactly one resource, no trailing slash.

This is blocking direct Fabric Core MCP authentication in both Codex CLI and Codex Desktop, which share the Codex MCP OAuth path.

View original on GitHub ↗