OAuth redirect URI port mismatch breaks login to most MCP servers
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 52/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- node.js
- 領域
- authentication, cli
調査の方向性
Start with the /mcp add OAuth flow and inspect the published client-metadata.json alongside the loopback listener in the shipped SEA binary. Compare the advertised redirect URI with the runtime redirect_uri, then verify the chosen behavior against a strict-matching MCP OAuth server and the RFC 8252 loopback requirement.
索引モデルが issue の本文から書いたものです。
説明
OAuth redirect URI port mismatch breaks login to most MCP servers
Summary
copilot CLI publishes a CIMD (Client ID Metadata Document) that declares a
single loopback redirect URI on a fixed port, but at runtime the CLI binds an
ephemeral loopback port and sends that port in the OAuth redirect_uri
parameter. GitHub's own OAuth server accepts the mismatch (per RFC 8252 §7.3
loopback matching), but many third-party OAuth servers — including
Entra/Azure-fronted MCP servers — do strict string matching against the
registered redirect_uris and reject the request.
The result is that authentication fails against almost every non-GitHub MCP
server users try to connect. Claude Code and Codex CLI are not affected in
the same environments.
Environment
- CLI version:
GitHub Copilot CLI 1.0.88 - OS: macOS (arm64)
- Install: Homebrew cask
copilot-cli(SEA binary)
Reproducer
- Configure any MCP server whose OAuth authorize endpoint validates
redirect_uriby exact match against the CIMD'sredirect_urislist.
(Entra/Azure-fronted services typically behave this way.) - Trigger the OAuth flow from Copilot CLI:
/mcp add <server-url>(or however the server is registered), then log in. - The browser lands on the authorize endpoint, which returns:
{
"error": "invalid_request",
"error_description": "Redirect URI 'http://127.0.0.1:52752/' does not match CIMD redirect_uris.",
"state": "..."
}
The port (52752 above) changes on every attempt.
Expected behavior
The redirect_uri sent to the authorize endpoint should either:
- (a) match the port published in the CIMD, i.e.
http://127.0.0.1:33418/, so
strict-matching servers accept it; or - (b) rely on RFC 8252 §7.3 loopback matching and have the CIMD advertise
http://127.0.0.1/(no port), making clear to server implementers that
port-agnostic matching is expected.
Today it does neither: it publishes a specific port and then uses a different
one.
Actual behavior / root cause
The CLI's published metadata at
https://github.com/copilot/cli/client-metadata.json:
{
"client_id": "https://github.com/copilot/cli/client-metadata.json",
"client_name": "GitHub Copilot CLI",
"application_type": "native",
"redirect_uris": ["http://127.0.0.1:33418/"],
...
}
But the CLI's OAuth loopback listener is bound with port 0 (verifiable by
inspecting the SEA blob inside the shipped binary):
// Port 0 = let the OS pick a free ephemeral port. Bind to loopback only.
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
const port = typeof address === "object" && address ? address.port : 0;
The dynamically-assigned port then flows into the OAuth redirect_uri, which
never equals 33418.
Impact
- Blocks Copilot CLI from authenticating against most third-party MCP servers,
which is a large and growing set as MCP adoption widens. - Internal reports at multiple organisations indicate the same failure pattern
across every non-GitHub MCP they've tried, with Claude Code / Codex CLI
unaffected in the same environments. - Users have no clean local workaround. The one lever we found —
COPILOT_MCP_CIMD_CLIENT_ID_URLoverriding the CIMD document URL — requires
self-hosting a metadata file that enumerates every ephemeral loopback port,
which is fragile and requires the MCP server to dynamically trust arbitrary
CIMDs.
Suggested fixes (either is sufficient)
- Bind the published port. Change the listener to
server.listen(33418, "127.0.0.1", …)with a fallback strategy (retry with
an ephemeral port only if 33418 is in use, and clearly document the
fallback), so the common case matches the CIMD exactly. - Publish port-agnostic CIMD. Change
redirect_urisin
client-metadata.jsonto["http://127.0.0.1/"]and rely on the RFC 8252
§7.3 loopback rule. This shifts the responsibility to non-conformant OAuth
servers, which is arguably correct, but will not fix real-world usage until
those servers are updated.
Option 1 is the most defensive; option 2 is the most spec-pure. A combination
(bind 33418 first, publish 127.0.0.1/) would maximise interoperability.
References
- RFC 8252 §7.3 (Loopback Interface Redirection): loopback redirects SHOULD be
matched ignoring the port component. - OAuth 2.0 for Native Apps client identity metadata document (CIMD) spec.
Drafted with GitHub Copilot CLI.
- 主要言語
- Shell
- スター
- 11.2k
- フォーク
- 1.9k
- 平均マージ
- 17時間 6分
- マージ済み PR(30日)
- 5
環境構築
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
github/copilot-cli のほかの issue
-
triage
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
github/copilot-cli#4963 ·
メンテナーはふだん 1 日以内に返信
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
github/copilot-cli#4932 ·
メンテナーはふだん 1 日以内に返信
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
github/copilot-cli#4909 ·
メンテナーはふだん 1 日以内に返信
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
github/copilot-cli#4906 ·
メンテナーはふだん 1 日以内に返信
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
github/copilot-cli#4848 ·
メンテナーはふだん 1 日以内に返信
github/copilot-cli の issue をすべて見る
似ている issue
-
package-update
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
bug needs triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
vllm-project/vllm-metal#841 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
obra/superpowers#2394 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
CachyOS/cachyos-aur-derived#772 ·
メンテナーはふだん 1 日以内に返信