Implement OAuth 2.1 + Entra ID authentication for an MCP server using a lightweight AS metadata proxy — handling RFC 9728 protected resource metadata, RFC 8414 AS metadata, and a /register endpoint that eliminates client_id prompts for all MCP clients. WHEN: adding OAuth to an MCP server, MCP clients ask users to paste a client_id, authorization redirects go to the wrong endpoint, or debugging Entra DCR limitations.
Implement OAuth 2.1 + Entra ID authentication for an MCP server using a lightweight AS metadata proxy — handling RFC 9728 protected resource metadata, RFC 8414 AS metadata, and a /register endpoint that eliminates client_id prompts for all MCP clients. WHEN: adding OAuth to an MCP server, MCP clients ask users to paste a client_id, authorization redirects go to the wrong endpoint, or debugging Entra DCR limitations.
domain
security-authentication
confidence
high
source
earned
Skill: MCP OAuth + Entra ID Integration
When to invoke
Use this skill when:
Adding/debugging OAuth 2.1 authentication to an MCP server
MCP clients prompt users for a client_id that should be automatic
MCP clients redirect to the wrong /authorize endpoint (server instead of Entra)
Client → GET /mcp → 401 WWW-Authenticate: Bearer resource_metadata="..."
→ GET /.well-known/oauth-protected-resource
returns: { authorization_servers: ["..."] }
→ GET {auth_server}/.well-known/oauth-authorization-server
(or openid-configuration)
returns: { authorization_endpoint, token_endpoint, registration_endpoint? }
→ POST {registration_endpoint} ← only if client has no pre-registered client_id
returns: { client_id }
→ redirect user to authorization_endpoint with client_id + PKCE
Entra ID limitation: Does not support RFC 7591 Dynamic Client Registration (DCR) for
public clients. VS Code has a hardcoded client_id (aebc6443-996d-45c2-90f0-388ff96faa56)
and does not need DCR. Other MCP clients (Claude Desktop, Cline, custom) do not, so they
ask the user to paste a client_id.
Solution pattern: OAuth Proxy
Run PoshMcp itself as a lightweight AS metadata proxy:
X-Forwarded-* headers — Azure Container Apps sets X-Forwarded-Proto=https and
X-Forwarded-Host={fqdn}. Always use these when building absolute URLs in endpoints.
Otherwise the issuer and registration_endpoint will show http:// instead of https://.
Entra tenant URL format — Use https://login.microsoftonline.com/{tenant}/v2.0 as
the Entra issuer, NOT https://login.microsoftonline.com/{tenant} (the /v2.0 suffix is
required for modern tokens and the correct /.well-known/openid-configuration endpoint).
Entra client authorization — Any client_id returned by /register must be pre-authorized
in the Entra app registration under Expose an API → Authorized client applications.
Without this, Entra returns AADSTS65001 ("User or administrator has not consented").
VS Code built-in client_id = aebc6443-996d-45c2-90f0-388ff96faa56.
This must be added to Authorized client applications in the Entra app registration.
OAuth proxy vs pointing directly to Entra — Pointing AuthorizationServers directly
to Entra works for VS Code but not for generic MCP clients (no DCR). The proxy approach
handles both via the /register fallback.
StringValues.FirstOrDefault() — In ASP.NET Core, Request.Headers["X-Forwarded-Proto"]
returns StringValues, not string. Call (string?)req.Headers["X-Forwarded-Proto"]
or add using System.Linq and use .FirstOrDefault().