Can't implement a CIMD client if auth provider doesn't put "none" first in it's list of supported token auth methods
Les mainteneurs répondent en général sous 2 jours
@mikeholczer y travaille déjà.
Depuis le 1/6/2026.
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 62/100
- Type d'issue
- Bug
- Clarté
- Plutôt claire
- Activité
- Active
- Stack technique
- csharp
- Domaine
- api, authentication, backend-api-design
Piste de recherche
Commencez dans ClientOAuthProvider.GetAccessTokenAsync, ApplyClientIdMetadataDocument et CreateTokenRequest, puis suivez la manière dont DCR et les métadonnées du serveur définissent _tokenEndpointAuthMethod. Utilisez les tests before/after signalés comme point de départ et ajoutez une couverture pour CIMD avec none, en vérifiant la précédence explicit → DCR → server-advertised ainsi qu’une requête de token qui inclut client_id plutôt que des identifiants Basic.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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:
- Use an authorization server that supports CIMD (
client_id_metadata_document_supported: true) and advertisesclient_secret_basicbeforenoneintoken_endpoint_auth_methods_supported(e.g. Auth0). - Host a CIMD document that declares
"token_endpoint_auth_method": "none". - 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); - Complete the authorization-code flow. The authorize leg succeeds and returns a code, but the token-exchange
POST /tokenis sent asAuthorization: Basic base64(<cimd-url>:)with noclient_idin the body. - The authorization server responds
401 access_deniedandCreateAsyncthrows.
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— theTokenEndpointAuthMethodsSupported?.FirstOrDefault()selection and the CIMD handling are unchanged). - Root causes: (1)
ApplyClientIdMetadataDocumentdiscards the metadata document'stoken_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 —CreateTokenRequestonly emitsclient_secret_basic,client_secret_post, ornone— sononeis 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.
- Langage dominant
- C#
- Étoiles
- 4.6k
- Forks
- 852
- Merge moyen
- 9 j 3 h
- PR mergées (30 j)
- 3
Préparer son environnement
Lance le conteneur de développement du projet dans votre navigateur, avec votre propre compte GitHub.
- Aucun Dockerfile ni fichier Docker Compose
- Aucun modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de modelcontextprotocol/csharp-sdk
-
Reserved URI-template expansion throws for supplementary Unicode charactersPeut-être pris @pournasserian l’a pris il y a 5 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
modelcontextprotocol/csharp-sdk#1913 · 1 commentaire ·
Les mainteneurs répondent en général sous 2 jours
-
ClaimsPrincipal parameter injection sample requestPeut-être pris @utsavjain2809 l’a pris il y a 15 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
modelcontextprotocol/csharp-sdk#1899 ·
Les mainteneurs répondent en général sous 2 jours
-
Document ClientOAuthOptions.ScopeSelector usagePeut-être pris @z0rimo l’a pris il y a 39 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
modelcontextprotocol/csharp-sdk#1867 · 1 commentaire ·
Les mainteneurs répondent en général sous 2 jours
-
HTTP+SSE client: POST responses are never disposed, leaking one connection per sent messagePeut-être pris @yalcinfu22 l’a pris il y a 53 jours. Ouverte
Difficulté 1/5 Moins d'une heure Accessibilité débutants 88/100
modelcontextprotocol/csharp-sdk#1840 · 1 commentaire ·
Les mainteneurs répondent en général sous 2 jours
-
enhancement needs confirmation
Difficulté 2/5 1-3 heures Accessibilité débutants 64/100
modelcontextprotocol/csharp-sdk#678 · 1 commentaire ·
Les mainteneurs répondent en général sous 2 jours
Toutes les issues de modelcontextprotocol/csharp-sdk
Issues similaires
-
bug priority: P2
Difficulté 1/5 1-3 heures Accessibilité débutants 84/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 77/100
Les mainteneurs répondent en général sous 1 jour
-
[Docs] README/PRIVACY still name AppCenter although v1.5.6.0+ uses the Microsoft Store Services SDKOuverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
-
needs-triage
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
Azure/azure-sdk-tools#17317 ·
Les mainteneurs répondent en général sous 1 jour
-
Test
Difficulté 2/5 1-3 heures Accessibilité débutants 69/100
Les mainteneurs répondent en général sous 1 jour