Azure API Management MCP server: 401 after OAuth sign-in when the identity tenant is Azure AD B2C (same setup works with Entra ID P2 tenant)

Rishi Jha 0 Reputation points
2026-10-01T06:52:31.9966667+00:00

Service

Azure API Management (Expose REST API as MCP Server), Azure AD B2C, Microsoft Entra ID, Azure Functions backend. The MCP Host is Claude Desktop, using a custom connector.

Scenario

We use a two-tenant setup. One tenant hosts our resources, and our users live in a separate tenant. We exposed an existing REST API as an MCP server through APIM, secured with OAuth 2.1 (authorization code + PKCE, public client, no secret).

This setup works end to end when the user tenant is a Microsoft Entra ID tenant (P2 licensed). We are now trying the same setup with an Azure AD B2C tenant as the user tenant, and it fails.

The APIM inbound policy on the MCP server does three things:

  1. If a request has no Authorization header, it returns 401 with WWW-Authenticate: Bearer so the MCP client starts the OAuth flow.
  2. If a request has Authorization: Bearer <token>, it validates the token's signature, issuer and audience against the user tenant using validate-azure-ad-token with tenant-id.
  3. If validation succeeds, it forwards the request unchanged to the tools.

Result

With the Entra ID user tenant, sign-in completes and MCP calls succeed.

With the Azure AD B2C user tenant, the browser completes sign-in and shows a success page. After that, the Claude Desktop shows Server returned 401 Unauthorized on re-authentication. From our side we can't tell which of these is happening:

  • (a) The authorization code to token exchange at the B2C /token endpoint failed silently after the browser showed success, so no token was issued and the client retried without one, or
  • (b) A token was issued but our APIM policy rejected it, for example because of the wrong audience, issuer or signing key.

User's image

Environment

  • Tenant A (resource tenant, Microsoft Entra ID): APIM instance, MCP server, backend Function App
  • Tenant B (user tenant): previously a Microsoft Entra ID P2 tenant (working); now an Azure AD B2C tenant (failing)
  • App registration live in the user tenant
  • APIM tier: [Basic v2]
  • Token version: [v2]

Supporting materials

Sanitized inbound policy:

<policies>
    <inbound>
        <choose>
            <when condition="@(!context.Request.Headers.ContainsKey("Authorization"))">
                <return-response>
                    <set-status code="401" reason="Unauthorized" />
                    <set-header name="WWW-Authenticate" exists-action="override">
                        <value>Bearer</value>
                    </set-header>
                </return-response>
            </when>
        </choose>
        <validate-azure-ad-token tenant-id="<b2c-tenant-id>" header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
            <client-application-ids>
                <application-id><app-client-id></application-id>
            </client-application-ids>
            <audiences>
                <audience><app-client-id></audience>
                <audience>https://verified-domain/<app-client-id></audience> # This was api://<app-client-id> in P2 Setup
            </audiences>
        </validate-azure-ad-token>
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Question

When OAuth sign-in against Azure AD B2C looks successful in the browser but the client then gets a 401 from APIM, what is the recommended way to find out whether the failure happened at the B2C /token exchange or in the APIM validation policy, given that the same policy works with an Entra ID user tenant?

Azure API Management
Azure API Management

An Azure service that provides a hybrid, multi-cloud management platform for APIs.

0 comments No comments

1 answer

Sort by: Oldest
  1. Silvio Lorenzo Torre 165 Reputation points
    2026-11-02T18:58:36.1566667+00:00

    Hi Rishi,

    The first thing I would do is separate “APIM did not receive an access token” from “APIM received a token but rejected it.”

    A successful browser sign-in only confirms that the interactive authorization step completed. It does not prove that the authorization code was successfully exchanged for an API access token or that the MCP client attached that token to the subsequent APIM request.

    1. Determine whether APIM receives the bearer token

    Reproduce the request in a controlled environment and inspect APIM request processing.

    Current APIM request tracing uses a time-limited debug credential passed in the Apim-Debug-Authorization header. The former Ocp-Apim-Trace mechanism is no longer supported.

    If the request reaching APIM has no: Authorization: Bearer <token> then the failure is upstream of token validation: for example code exchange, requested scopes, token storage, or subsequent token attachment by the MCP client.

    If the bearer token reaches APIM and processing fails at the validation policy, the OAuth flow progressed far enough to obtain and send a token, and you can concentrate on issuer, audience, signing keys, or policy configuration.

    For troubleshooting, i suggest you to assign an id to the validation policy and inspect context.LastError.Source, Reason, Message, and PolicyId from on-error.

    Caveat:

    • Do not expose these diagnostics to production clients.

    Do not log or publish the raw access token. Inspect only the relevant claims in a controlled environment, especially iss, aud, kid, and the B2C policy/user-flow claim (tfp or acr, depending on the token).

    2. Use the B2C validation pattern documented by Microsoft

    This is also where I would change the current APIM policy.

    For Azure AD B2C, Microsoft documents validate-jwt using the OpenID Connect configuration endpoint of the actual B2C user flow.

    For example:

    <validate-jwt
        id="validate-b2c-token"
        header-name="Authorization"
        require-scheme="Bearer"
        failed-validation-httpcode="401"
        failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
    
        <openid-config
            url="https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<user-flow>/v2.0/.well-known/openid-configuration" />
    
        <audiences>
            <audience><exact-value-expected-in-the-access-token-aud-claim></audience>
        </audiences>
    
        <issuers>
            <issuer><issuer-published-by-the-user-flow-metadata></issuer>
        </issuers>
    </validate-jwt>
    

    Use the issuer published by that specific user-flow metadata and the audience actually expected for the API.

    I would not add multiple guessed audience formats merely to make validation succeed.

    Also verify that the authorization request includes a scope exposed by the API. Successfully completing B2C interactive sign-in with only identity scopes such as openid and profile does not by itself establish that an access token suitable for calling this API was issued.

    3. Remove AI (Claude) from the equation

    A useful isolation test is to use a separate OAuth client configured against the same B2C user flow and API scope:

    Complete authorization code + PKCE.

    Obtain the access token.

    Inspect its non-sensitive claims.

    Call the APIM endpoint directly using Authorization: Bearer <token>.

    Inspect the APIM result/trace.

    If this direct request succeeds, the APIM/B2C validation path is working and the remaining problem is likely in the MCP client's OAuth discovery, code exchange, scope request, token storage, or token attachment.

    If it fails, the APIM diagnostics and the token claims should identify whether the mismatch is the issuer, audience, signing key, or another validation requirement.

    So I would suggest two changes first:

    1. verify whether the second request actually contains a bearer token;
    2. replace the B2C validation path with the documented validate-jwt + B2C user-flow metadata configuration.

    The fact that the existing validate-azure-ad-token configuration works against a regular Microsoft Entra tenant does not establish that the same validation model is appropriate for a policy-specific Azure AD B2C issuer.

    Hope is useful, please upvote the answer if the information helped you.

    Please note: This answer was partially prepared and translated into English with assistance from AI (ChatGPT). I reviewed the technical claims against the Microsoft documentation linked above.

    Ciao

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.