There is a special category of authentication bug designed to make a competent developer question every layer of the internet.

The connector works for you. It works repeatedly. The OAuth screen appears, the callback completes, and Claude can use the tools. Then a coworker tries the same connector and gets a vague failure. Your application logs show nothing—not an error, not a rejected request, not even proof that Claude called the server.

Naturally, you investigate Claude. Then the OAuth broker. Then token scopes, callback URLs, browser state, enterprise settings, and whether your coworker clicked the correct button on a Tuesday.

The actual problem may be one layer earlier: Azure Container Apps authentication can reject the request before your application ever sees it.

This is the story of that trap, how to recognize it, and how to avoid losing several days to a perfectly healthy application.

Visual placeholder: Opening animation. Two people add the same MCP connector. “Developer” gets a green success result; “Coworker” gets a red connection failure. The server’s application-log panel stays blank.

The architecture that creates the mystery

Imagine a remote MCP server deployed on Azure Container Apps. The application implements its own OAuth endpoints and validates bearer tokens at /mcp. Azure’s built-in authentication feature—often called Easy Auth—is also enabled in front of the container.

Your request path is therefore not simply:

Claude → your application

It is:

Claude → Azure authentication sidecar → your application

That sidecar is useful. It can validate Microsoft Entra tokens, establish a user principal, and enforce an authorization policy without requiring your application to reimplement every platform concern.

It can also deny a valid request before Express, FastAPI, or whatever runs your MCP server receives a single byte.

That is why the empty application logs are not evidence that Claude never called your URL. They may be evidence that an upstream gate stopped the request.

Visual placeholder: Layer diagram with a red stop sign between Claude and the application. Label the stop sign “Easy Auth authorization policy — 403 before app code.”

The misleading setting: Allow Anonymous

The configuration name unauthenticatedClientAction: AllowAnonymous looks comfortingly decisive. It is tempting to read it as “Easy Auth is not enforcing access; my app handles authentication.”

That interpretation is incomplete.

The setting governs what happens when a request has no authenticated identity. A credential-less request may be allowed through to your app. But when a request includes a token that Azure can validate, the platform can establish a principal and then apply its default authorization policy.

In the deployment that inspired this article, an authenticated principal missing from allowedPrincipals—and not covered by allowedApplications—received a 403 before the application ran. Azure exposes both lists under the Microsoft Entra provider’s defaultAuthorizationPolicy, even though they may not be obvious in the portal’s top-level authentication summary.

So you can observe all three of these at once:

  • An unauthenticated health request reaches the application.
  • Your own authenticated MCP request reaches the application.
  • Your coworker’s valid authenticated request never reaches the application.

No contradiction is required. The requests take different branches through the platform policy.

The two-list problem

In a typical enterprise setup, a new user may need to be approved in two places.

First, the user needs access to the Microsoft Entra enterprise application. If user assignment is required, an administrator must assign the user or a group to the application.

Second, the same user may need to appear in the Azure Container App authentication policy’s allowedPrincipals identities list—or be covered by an equivalent allowed group or application rule.

The effective audience is the intersection:

People assigned to the Entra app ∩ People allowed by the Container App policy

Being on either list alone is not enough.

This is particularly easy to miss when the two permissions have different owners. An identity administrator controls enterprise-app assignment. An application owner controls the Container App. Each person can truthfully say, “The user is approved on my side.” The system can still reject the user.

Visual placeholder: Venn diagram. Left circle: “Entra app assignment.” Right circle: “Container App allowed principals.” The overlap is labeled “People who can actually connect.”

Why it looks like a client-side failure

Remote MCP adds another layer of indirection. The user is not manually sending a request to /mcp; Claude is doing it after an OAuth flow. The UI may summarize several possible failures as “connection failed” or “could not authenticate.”

Meanwhile, your app logs show no request because the Azure sidecar produced the response. If you look only at application stdout, the most plausible story is that the client never called you.

That story sends debugging in the wrong direction.

The fix is to observe each boundary independently:

  1. Did the authorization endpoint receive the initial request?
  2. Did the token endpoint complete successfully?
  3. Was an access token issued with the expected issuer, audience, and scopes?
  4. Did Azure ingress receive the subsequent MCP request?
  5. Did the Easy Auth layer accept or reject its principal?
  6. Did the application receive the request?

Do not collapse “OAuth succeeded” and “the protected resource accepted the token” into one event. They are different requests and can fail under different policies.

A fast diagnostic sequence

When the connector works for one person but not another, resist the urge to change code. Compare identity and policy state first.

1. Confirm the failure is user-specific

Have the working and failing users repeat the same deterministic operation. Avoid a broad Claude prompt that may or may not choose the tool.

2. Compare Entra assignment

Check whether both identities are assigned to the enterprise application or covered by the same assigned group. Record object IDs carefully; display names and email addresses are friendly labels, not reliable policy keys.

3. Inspect the complete Container App auth configuration

Read the live authConfigs/current resource and examine the Azure Active Directory provider’s validation and default authorization policy. Do not assume the portal summary exposes every consequential field.

Look for both:

  • allowedApplications
  • allowedPrincipals.identities

4. Compare platform logs with application logs

Application logs answer “What did my code do?” Platform and ingress diagnostics answer “Did the request get to my code?” You need both.

5. Add one user, then retest

Make the smallest reversible policy change. If the user immediately connects without a new deployment, you have strong evidence that the platform allowlist—not the OAuth implementation—was the root cause.

Visual placeholder: Troubleshooting flowchart ending in “No app log entry + platform 403 → inspect Easy Auth defaultAuthorizationPolicy.”

Do not casually edit the allowlist

Authorization arrays deserve the same caution as firewall rules. A malformed update can lock out the people who were already working.

Prefer a read-modify-write process:

  1. Retrieve the current authentication configuration.
  2. Preserve every unrelated setting and existing identity.
  3. Add the new identity once.
  4. Validate the resulting JSON structure.
  5. Submit the complete updated resource.
  6. Read it back and verify the stored values.
  7. Test an existing user, the new user, and an unapproved user.

Be careful with command-line convenience syntax that serializes array values. Quoting mistakes can store literal quote characters inside identity strings. The update command may report success while every entry becomes unusable.

When access control is involved, “the command exited zero” is not verification.

Make onboarding a single checklist

Once you understand the two-list model, encode it in the operating procedure.

A good user-onboarding checklist includes:

  • Entra enterprise-app assignment
  • Container App allowed-principal or allowed-group membership
  • Claude organization connector availability
  • Individual OAuth connection completed
  • Expected MCP tools enabled
  • One deterministic test call
  • A corresponding offboarding procedure for every list

If two administrators own different steps, name both roles in the checklist. Better yet, use a shared group as the source of truth where your security model permits it. Manually synchronizing duplicate user arrays works right up until it does not.

The larger lesson

Modern cloud requests pass through a stack of helpful machinery: DNS, ingress, web application firewalls, platform authentication, your own authorization middleware, and downstream API permissions. Any one of those layers can reject a request.

An empty application log does not prove the client was idle. It proves only that your application did not observe the request.

When an integration works for its creator but not its users, draw the full request path and list every gate. Then compare the working and failing identities at each gate before rewriting code.

Authentication bugs are still annoying. But they become much less mystical once every invisible bouncer has a name.

References