github / github/copilot-cli

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

オープン
#4,582 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

triage
主要言語
Shell
スター
11.2k
フォーク
1.9k
平均マージ
14時間 16分
マージ済み PR(30日)
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. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

~/.copilot/mcp-config.json で構成されたリモート HTTP サーバーの MCP 設定 Sign in フローから始め、次に、静的な oauthClientId とともに oauth-authorization-server および oauth-protected-resource のメタデータがどのように使用されるかを追跡します。Entra ID に対して再現し、認可、トークン交換、リフレッシュを通じて scope が伝播することを確認します。関連するコンテキストとして issue #4464 を使用してください。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
azure
領域
api, authentication
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
55/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。