Skip to content

Unconditional prompt=consent (when offline_access in scope) blocks OAuth in Entra tenants with user consent disabled + admin consent granted #2867

Description

@sonmaximum

Symptom

packages/client/src/client/auth.ts, in startAuthorization:

if (scope?.split(' ').includes('offline_access')) {
    authorizationUrl.searchParams.append('prompt', 'consent');
}

In enterprise Entra tenants where:

  • User consent is disabled (Microsoft's recommended default)
  • Admin consent granted tenant-wide for the app (AllPrincipals OAuth2PermissionGrant present)

prompt=consent bypasses the existing admin grants and forces Entra to show the consent screen. Non-admin users hit AADSTS90095: Admin consent is required on every reconnect. Unrecoverable, since the admin already consented. Approving the resulting admin-consent request does not change tenant state; the next connect triggers another same consent request.

Verified in our tenant against a Microsoft-hosted MCP server (WorkIQ Mail Tool): manually removing &prompt=consent from the SDK-generated authorize URL and continuing the flow returns tokens immediately, no consent screen. Grants are respected; the SDK-added parameter is the sole blocker.

Repro

Cline (using this SDK): blocks with AADSTS90095:

https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize
  ?response_type=code
  &client_id=<redacted>
  &redirect_uri=http://127.0.0.1:1456/mcp/oauth/callback
  &scope=<resource>/.default+openid+profile+offline_access
  &prompt=consent   ← added by SDK, sole blocker
  &resource=<resource>

The &prompt=consent in this URL is what the SDK code shown above appends. Removing it manually (per the Symptom section above) returns tokens with no consent screen - confirming it as the sole blocker.

Fix

Drop the unconditional add.

Spec basis: OIDC Core §11's prompt=consent obligation is on the authorization server, not the client. §11 notes that prompt=consent "can be used" by the AS - not required to be sent by the client. #681 introduced the client-side add as a defensive measure; the underlying spec doesn't ask for it.

Precedent: Azure CLI, VS Code, and other established OAuth clients requesting offline_access against Entra don't force the prompt=consent parameter client-side and operate correctly in the same enterprise-tenant configuration where this SDK currently breaks.

Downstream clients that want to force re-consent for a specific high-risk flow can add the parameter themselves at the call site.

Impact

Blocks every non-admin end-user in enterprise Entra tenants for any MCP server the client OAuths against.

Related:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    v1Issues / PRs related to v1.xv2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions