Repository navigation
OAuth authentication request fails with MS Entra-ID #648
Description
Activity
I get that too! According to https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow the resource is not part of the request.
I think this part should be as simple as MSAL - on the server just use the existing ASP.NET Authentication & Authorization mechanisms & UX (e.g. [Authorize] attribute with a role over the MCP Server/Tool - e.g. I would like to separate the role of agent/AI vs user roles) and on the client side, simply use MSAL to get the token (e.g. authorization flow, client secret, device code, etc.) and add it to the protocol as we do for HttpClient (Authorization header: Bearer token).
The MCP client should not perform any OAuth functionalities directly like opening the browser, getting the token as there are libraries for that way much better coded/tested.
I got it to work (i.e. the authentication) using this workaround (i.e. by removing the resource and adding the grant_type) but I get an exception when creating the MCP client - essentially for the same reason (resource is being sent -
).["resource"] = protectedResourceMetadata.Resource.ToString(), // on server services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme; }) .AddMcp(options => { options.ResourceMetadata = new() { Resource = new Uri("http://localhost:53969/sse"), AuthorizationServers = { new Uri("https://login.microsoftonline.com/<tenant>/v2.0") }, ScopesSupported = ["some_scope"], // from Entra App Registration ResourceName = "MCP API", }; }) .AddMicrosoftIdentityWebApi(configuration.GetSection("Authentication")); // in client var transport = new SseClientTransport(new() { Endpoint = new Uri("http://localhost:53969/sse"), Name = "Secure MCP Client", OAuth = new() { ClientName = "API MCP Client", ClientId = "xxx", RedirectUri = new Uri("http://localhost:8080"), // correct redirect URL from Entra App Registration AuthorizationRedirectDelegate = HandleAuthorizationUrlAsync, } }, loggerFactory); // FAILS HERE - see below var mcpClient = await McpClientFactory.CreateAsync( transport, loggerFactory: loggerFactory); static async Task<string?> HandleAuthorizationUrlAsync(Uri authorizationUrl, Uri redirectUri, CancellationToken cancellationToken) { Console.WriteLine("Starting OAuth authorization flow..."); // remove 'resource' query parameter if present var uriBuilder = new UriBuilder(authorizationUrl); var query = HttpUtility.ParseQueryString(uriBuilder.Query); query.Remove("resource"); uriBuilder.Query = query.ToString(); // add 'grant_type' query parameter if not present if (!query.AllKeys.Contains("grant_type")) { query["grant_type"] = "authorization_code"; uriBuilder.Query = query.ToString(); } authorizationUrl = uriBuilder.Uri; Console.WriteLine($"Opening browser to: {authorizationUrl}"); // rest of the code }Exception:
Listening for OAuth callback on: http://localhost:8080/ Authorization code received successfully. warn: ModelContextProtocol.Client.SseClientSessionTransport[1753402347] Secure API MCP Client transport message reading failed. System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (Bad Request). at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() at ModelContextProtocol.Authentication.ClientOAuthProvider.FetchTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.ExchangeCodeForTokenAsync(ProtectedResourceMetadata protectedResourceMetadata, AuthorizationServerMetadata authServerMetadata, String authorizationCode, String codeVerifier, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.InitiateAuthorizationCodeFlowAsync(ProtectedResourceMetadata protectedResourceMetadata, AuthorizationServerMetadata authServerMetadata, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.PerformOAuthAuthorizationAsync(HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.HandleUnauthorizedResponseAsync(String scheme, HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.AuthenticatingMcpHttpClient.HandleUnauthorizedResponseAsync(HttpRequestMessage originalRequest, JsonRpcMessage originalJsonRpcMessage, HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.AuthenticatingMcpHttpClient.SendAsync(HttpRequestMessage request, JsonRpcMessage message, CancellationToken cancellationToken) at ModelContextProtocol.Client.SseClientSessionTransport.ReceiveMessagesAsync(CancellationToken cancellationToken) fail: ModelContextProtocol.Client.SseClientSessionTransport[1985454809] Secure API MCP Client transport connect failed. System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (Bad Request). at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() at ModelContextProtocol.Authentication.ClientOAuthProvider.FetchTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.ExchangeCodeForTokenAsync(ProtectedResourceMetadata protectedResourceMetadata, AuthorizationServerMetadata authServerMetadata, String authorizationCode, String codeVerifier, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.InitiateAuthorizationCodeFlowAsync(ProtectedResourceMetadata protectedResourceMetadata, AuthorizationServerMetadata authServerMetadata, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.PerformOAuthAuthorizationAsync(HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.HandleUnauthorizedResponseAsync(String scheme, HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.AuthenticatingMcpHttpClient.HandleUnauthorizedResponseAsync(HttpRequestMessage originalRequest, JsonRpcMessage originalJsonRpcMessage, HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.AuthenticatingMcpHttpClient.SendAsync(HttpRequestMessage request, JsonRpcMessage message, CancellationToken cancellationToken) at ModelContextProtocol.Client.SseClientSessionTransport.ReceiveMessagesAsync(CancellationToken cancellationToken) at ModelContextProtocol.Client.SseClientSessionTransport.ConnectAsync(CancellationToken cancellationToken) fail: ModelContextProtocol.Client.McpClient[1155727496] Secure API MCP Client client initialization error. System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (Bad Request). at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() at ModelContextProtocol.Authentication.ClientOAuthProvider.FetchTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.ExchangeCodeForTokenAsync(ProtectedResourceMetadata protectedResourceMetadata, AuthorizationServerMetadata authServerMetadata, String authorizationCode, String codeVerifier, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.InitiateAuthorizationCodeFlowAsync(ProtectedResourceMetadata protectedResourceMetadata, AuthorizationServerMetadata authServerMetadata, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.PerformOAuthAuthorizationAsync(HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.ClientOAuthProvider.HandleUnauthorizedResponseAsync(String scheme, HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.AuthenticatingMcpHttpClient.HandleUnauthorizedResponseAsync(HttpRequestMessage originalRequest, JsonRpcMessage originalJsonRpcMessage, HttpResponseMessage response, CancellationToken cancellationToken) at ModelContextProtocol.Authentication.AuthenticatingMcpHttpClient.SendAsync(HttpRequestMessage request, JsonRpcMessage message, CancellationToken cancellationToken) at ModelContextProtocol.Client.SseClientSessionTransport.ReceiveMessagesAsync(CancellationToken cancellationToken) at ModelContextProtocol.Client.SseClientSessionTransport.CloseAsync() at ModelContextProtocol.Client.SseClientSessionTransport.ConnectAsync(CancellationToken cancellationToken) at ModelContextProtocol.Client.AutoDetectingClientSessionTransport.InitializeSseTransportAsync(JsonRpcMessage message, CancellationToken cancellationToken) at ModelContextProtocol.Client.AutoDetectingClientSessionTransport.InitializeSseTransportAsync(JsonRpcMessage message, CancellationToken cancellationToken) at ModelContextProtocol.Client.AutoDetectingClientSessionTransport.InitializeAsync(JsonRpcMessage message, CancellationToken cancellationToken) at ModelContextProtocol.Client.AutoDetectingClientSessionTransport.InitializeAsync(JsonRpcMessage message, CancellationToken cancellationToken) at ModelContextProtocol.McpSession.SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken) at ModelContextProtocol.McpEndpointExtensions.SendRequestAsync[TParameters,TResult](IMcpEndpoint endpoint, String method, TParameters parameters, JsonTypeInfo`1 parametersTypeInfo, JsonTypeInfo`1 resultTypeInfo, RequestId requestId, CancellationToken cancellationToken) at ModelContextProtocol.Client.McpClient.ConnectAsync(CancellationToken cancellationToken)- addedneeds confirmationUnclear if still relevantUnclear if still relevant
on Feb 24, 2026 - marked ClientOAuthProvider does not work with MS Entra #939 as a duplicate of this issue
on Feb 24, 2026 - addedready for workHas enough information to startHas enough information to startand removedneeds confirmationUnclear if still relevantUnclear if still relevant
on Feb 24, 2026 - added a commit that references this issue
on Feb 28, 2026 guys, this generated resource query string with entra is blocking us from using it as an IDP for copilot. Can someone please provide a workaround for this? As mentioned previously even when i remove the resource QS manually , the mcp sdk client receives the same error. Is the current state of the mcp sdk not compatible with using entra as an IDP? If it is, can someone please point us in the right direction?
Reacted by Erwin@naqvir90 I'm also waiting for this issue. But I have a working setup here - https://github.com/erwinkramer/bank-api, but it's not using the SDK and is just based on an OpenAPI to MCP generator (with Entra ID auth), maybe that works for you too. This is fully tested with the GitHub Copilot client.
- addedbugSomething isn't workingSomething isn't workingP2Moderate issues, valuable feature requestsModerate issues, valuable feature requests
on Jul 19, 2026 Context from #741 (closed as a duplicate of this issue): authenticating an MCP client against Microsoft Entra ID fails with
AADSTS901002: The 'resource' request parameter is not supported. It occurs on both the authorization-code request and the token request. The reporter confirmed that removing theresourceparameter (patchingClientOAuthProvider.cslocally) resolves it -- so the SDK unconditionally sendingresourcein its OAuth requests is the blocker for using Entra ID as an authorization server.Reacted by Erwin- marked EntraID doesn't support 'resource' parameter when getting auth-code and token #741 as a duplicate of this issue
on Jul 19, 2026
Hi, I just checked out the 0.3.0-preview.3 release and I modified the ProtectedMCPServer and ProtectedMCPClient samples to use MS Entra-ID as OAUTH server (see code snippets below):
The URL that is created by the mcp server for starting the OAUTH flow looks like this:
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize?client_id=xxxxx&redirect_uri=http%3a%2f%2flocalhost%3a1179%2fcallback&response_type=code&code_challenge=q09KNTJ_gyVsLnvjSSX46MYl_DcPTuNhosF6U5n9KOs&code_challenge_method=S256&resource=http%3a%2f%2flocalhost%3a7077%2f&scope=api%3a%2f%xxxx-xxxxx-xxxxx%2fmcp.toolsThis url contains a resource and a scope parameter.
But MS Entra-ID complains about the resource parameter, as in OAuth 2.0 it should be the scope parameter used:
AADSTS901002: The 'resource' request parameter is not supported.What is your idea or hint to solve this problem?
My changes:
Client: I added the ClientId which I configured in Azure portal
Server:
changed the OAuth server url:
var inMemoryOAuthServerUrl = "https://login.microsoftonline.com/<tenant-id>/v2.0";changed ScopesSupported analog to the Azure Portal definition:
ScopesSupported = ["api://7e7eaf63-375a-4a0d-9872-574fdb5e08d6/mcp.tools"],Thanks
Markus