github / github/copilot-cli

MCP OAuth authorize request omits 'scope' parameter for Entra ID servers with static oauthClientId, causing AADSTS900144

未关闭
#4,582 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

triage
主要语言
Shell
星标
11.2k
派生
1.9k
平均合并
14 小时 16 分钟
30 天内合并 PR
6

描述

Describe the bug

When signing in to a remote (type: http) MCP server whose authorization server is Microsoft Entra ID, configured with a statically-provided oauthClientId + oauthPublicClient: true (no Dynamic Client Registration), Copilot CLI opens the browser to Entra ID's /authorize endpoint without a scope query parameter at all, even though the server's OAuth metadata correctly advertises scopes_supported. Microsoft Entra ID's v2.0 endpoint requires scope on both the authorization request and the token exchange (unlike base RFC 6749, where it's optional), so the flow fails immediately with:

Sorry, but we're having trouble signing you in.

AADSTS900144: The request body must contain the following parameter: 'scope'.

This is very likely the same root-cause bug class as #4464 (silent refresh fails with AADSTS70011 due to mishandled scope on the refresh_token grant) — in both cases the OAuth client isn't correctly deriving/propagating the scope parameter for Entra ID flows built from server-advertised metadata. It's also functionally identical to anthropics/claude-code#69547, which reports the exact same AADSTS900144 error for the exact same scenario (pre-registered/static public client against an Entra ID-backed MCP server, since Entra ID doesn't support DCR) in a different MCP client, suggesting this is a well-known interoperability gap for MCP clients talking to Entra ID with a fixed client id.

Affected version

1.0.80 (Windows x64). Also reproduced on a locally-modified 1.0.79-era build before upgrading.

Steps to reproduce the behavior
  1. Configure a remote HTTP MCP server backed by Microsoft Entra ID with a statically-provided client id (no DCR), e.g. in ~/.copilot/mcp-config.json:
  {
     "mcpServers": {
       "example-server": {
         "type": "http",
         "url": "https://example.org",
         "oauthClientId": "<entra-app-client-id>",
         "oauthPublicClient": true
       }
     }
   }

The server's /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server documents are RFC 8414-compliant: authorization_servers matches the document's own issuer exactly, and authorization_endpoint/token_endpoint point at the real Microsoft Entra ID tenant endpoints (https://login.microsoftonline.com/<tenant>/oauth2/v2.0/authorize and .../token). The authorization-server metadata's scopes_supported correctly lists the resource's App ID URI scope, e.g. ["openid", "profile", "email", "api://<app-id>/access_as_user"].
2. In the app, open MCP settings and click Sign in for that server.
3. A browser window opens and navigates to Microsoft's /authorize endpoint. The observed request URL was:

  https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize
     ?response_type=code
     &client_id=<client-id>
     &state=<state>
     &code_challenge=<challenge>
     &code_challenge_method=S256
     &redirect_uri=http%3A%2F%2F127.0.0.1%3A<port>%2F
     &client_session=<session-id>

Note there is no scope= parameter anywhere in this URL.
4. Entra ID immediately rejects the request:

   AADSTS900144: The request body must contain the following parameter: 'scope'.
Expected behavior

The MCP OAuth client should build the scope parameter for the /authorize request (and again for the /token exchange) from the target server's advertised scopes_supported (from either the oauth-authorization-server or oauth-protected-resource metadata document), the same way it presumably does for servers that use Dynamic Client Registration. For Entra ID specifically, scope must be present on every leg of the flow (authorize request, token exchange, and refresh), since Entra ID's v2.0 endpoint treats scope as mandatory rather than optional.

Additional context
  • The corresponding server-side OAuth metadata was independently verified as fully RFC 8414 §3.3-compliant via repeated direct HTTP requests (issuer exactly matches authorization_servers, byte-for-byte, across 15 parallel requests) before this bug surfaced, ruling out a server-side metadata problem.
  • This may be related to how the client resolves scope when a server config supplies a static oauthClientId/oauthPublicClient: true and skips the registration_endpoint (Dynamic Client Registration) flow — DCR responses may carry scope information that the static-client path doesn't otherwise obtain from scopes_supported.
  • Related issues in this repo: #4464 (refresh-token grant mishandles Entra ID scope, AADSTS70011), #4439 / #4480 (separate RFC 8414 issuer-mismatch bugs, now fixed/in progress).
  • Related issue in a different MCP client with an identical error and scenario: anthropics/claude-code#69547.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 MCP 设置中针对配置在 ~/.copilot/mcp-config.json 中的远程 HTTP 服务器的 Sign in 流程开始,然后跟踪 oauth-authorization-server 和 oauth-protected-resource 元数据如何与静态 oauthClientId 一起使用。针对 Entra ID 重现该流程,并验证 scope 是否在授权、令牌交换和刷新过程中得到传递,同时将 issue #4464 作为相关上下文。

由索引模型根据 Issue 内容生成。

评估

技术栈
azure
领域
api, authentication
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
活跃
描述清晰度
基本清楚
新手友好度
55/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。