Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Can't implement a CIMD client if auth provider doesn't put "none" first in it's list of supported token auth methods

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

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

評価

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

調査の方向性

ClientOAuthProvider.GetAccessTokenAsync、ApplyClientIdMetadataDocument、CreateTokenRequest から始め、DCR とサーバーメタデータが _tokenEndpointAuthMethod をどのように設定するかを追跡します。報告されている before/after テストを出発点として、none を指定した CIMD のカバレッジを追加し、explicit → DCR → server-advertised の優先順位と、Basic 認証情報ではなく client_id を含むトークンリクエストを検証します。

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

説明

area-auth bug P2

Describe the bug

When authenticating as a public client identified by a Client ID Metadata Document (CIMD), ClientOAuthProvider can choose the wrong token-endpoint authentication method and the token exchange fails. This is the case when using Auth0 as an authentication provider.

The auth method is selected in GetAccessTokenAsync with:

_tokenEndpointAuthMethod ??= authServerMetadata.TokenEndpointAuthMethodsSupported?.FirstOrDefault();

Since it just takes the first method the authorization server advertises and ClientOAuthOptions exposes no way to override the method, if you don't have control over the authentication servers response, you can't get a token.

A CIMD client is a public client and must authenticate with none (proven via PKCE). But when the authorization server lists client_secret_basic ahead of none — as Auth0 does, advertising ["client_secret_basic","client_secret_post","private_key_jwt","none"], the provider picks client_secret_basic. CreateTokenRequest then sends the token request with an Authorization: Basic header built from the CIMD URL and an empty secret, and omits client_id from the body. A public/CIMD client has no client secret, so the authorization server rejects the exchange with 401 access_denied, and McpClient.CreateAsync throws.

Because the only place _tokenEndpointAuthMethod is set from client-specific data is the dynamic client registration (DCR) response, switching a working client from DCR to CIMD silently regresses the token-endpoint auth method.

To Reproduce
Steps to reproduce the behavior:

  1. Use an authorization server that supports CIMD (client_id_metadata_document_supported: true) and advertises client_secret_basic before none in token_endpoint_auth_methods_supported (e.g. Auth0).
  2. Host a CIMD document that declares "token_endpoint_auth_method": "none".
  3. Create a transport configured for CIMD only — no ClientId/ClientSecret, no DCR:
    await using var transport = new HttpClientTransport(new HttpClientTransportOptions
    {
        Endpoint = new Uri(mcpServerUrl),
        OAuth = new ClientOAuthOptions
        {
            RedirectUri = new Uri("https://localhost/auth/callback"),
            ClientMetadataDocumentUri = new Uri("https://example.com/client-metadata.json"),
            AuthorizationRedirectDelegate = HandleAuthorizationUrlAsync,
        },
    }, httpClient);
    
    await using var client = await McpClient.CreateAsync(transport);
    
  4. Complete the authorization-code flow. The authorize leg succeeds and returns a code, but the token-exchange POST /token is sent as Authorization: Basic base64(<cimd-url>:) with no client_id in the body.
  5. The authorization server responds 401 access_denied and CreateAsync throws.

Expected behavior
A CIMD public client should authenticate at the token endpoint with none (client id in the request body, PKCE as the proof of possession), matching the token_endpoint_auth_method declared in its metadata document, and the token exchange should succeed — regardless of which method the authorization server lists first. Pragmatically, it probably doesn't make sense for the client to read it's own CIMD, and the SDK should let the caller specify the token-endpoint authentication method.

Logs

End processing HTTP request after 126ms - 401   POST https://<issuer>/oauth/token
System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).
Response body: {"error":"access_denied","error_description":"Unauthorized"}
   at ModelContextProtocol.HttpResponseMessageExtensions.EnsureSuccessStatusCodeWithResponseBodyAsync(...)
   at ModelContextProtocol.Authentication.ClientOAuthProvider.ExchangeCodeForTokenAsync(...)
   at ModelContextProtocol.Authentication.ClientOAuthProvider.InitiateAuthorizationCodeFlowAsync(...)
   at ModelContextProtocol.Authentication.ClientOAuthProvider.GetAccessTokenAsync(...)

The corresponding token request omits client_id from the form body (it is Basic-encoded in the header with an empty secret), so the authorization server cannot identify the client.

Additional context

  • SDK version: 1.3.0 (also reproduces in 1.2.0 and on main — the TokenEndpointAuthMethodsSupported?.FirstOrDefault() selection and the CIMD handling are unchanged).
  • Root causes: (1) ApplyClientIdMetadataDocument discards the metadata document's token_endpoint_auth_method; (2) there is no option to set the token-endpoint auth method explicitly; so the provider falls back to the server's first-advertised method.
  • The confidential CIMD profile (private_key_jwt) is also not expressible — CreateTokenRequest only emits client_secret_basic, client_secret_post, or none — so none is the only CIMD profile the SDK can currently produce.

Proposed fix
Add an opt-in ClientOAuthOptions.TokenEndpointAuthMethod (used with precedence: explicit → DCR response → server-advertised first) and/or have ApplyClientIdMetadataDocument honor the document's declared method. I have a branch with the explicit-option fix plus before/after tests and am happy to open a PR.

主要言語
C#
スター
4.5k
フォーク
814
平均マージ
9日 19時間
マージ済み PR(30日)
4

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

modelcontextprotocol/csharp-sdk のほかの issue

modelcontextprotocol/csharp-sdk の issue をすべて見る

似ている issue

C# の issue をもっと見る

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

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