From e6c95ead2f7fbd9b97dcd80ecfff167700accea0 Mon Sep 17 00:00:00 2001 From: "robert.schie" Date: Thu, 2 Apr 2026 10:40:59 -0700 Subject: [PATCH] Added configurable token endpoint auth method selection The OAuth client currently selects the first token endpoint authentication method advertised by the authorization server. That can fail when servers expose multiple supported methods and the caller needs to prefer a different option based on client type or credentials. Added TokenEndpointAuthMethodSelector to ClientOAuthOptions and use it in ClientOAuthProvider when resolving the token endpoint auth method. Preserve the existing behavior by defaulting to the first advertised method when no selector is provided. --- .../Authentication/ClientOAuthOptions.cs | 14 ++++++++++++++ .../Authentication/ClientOAuthProvider.cs | 13 ++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs b/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs index 483e3643e..a2892083e 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs @@ -63,6 +63,20 @@ public sealed class ClientOAuthOptions /// public AuthorizationRedirectDelegate? AuthorizationRedirectDelegate { get; set; } + /// + /// Gets or sets the token endpoint authentication method selector function. + /// + /// + /// + /// This function is used to select which token endpoint authentication method to use when multiple methods are available. + /// If not specified, the first available method will be selected. + /// + /// + /// The function receives a list of supported authentication methods from the authorization server metadata and should return the selected method, or null if no suitable method is found. + /// + /// + public Func?, string?>? TokenEndpointAuthMethodSelector { get; set; } + /// /// Gets or sets the authorization server selector function. /// diff --git a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs index ecef8e15e..bd0cb7215 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs @@ -29,6 +29,7 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient private readonly Uri _redirectUri; private readonly string? _configuredScopes; private readonly IDictionary _additionalAuthorizationParameters; + private readonly Func?, string?> _tokenEndpointAuthMethodSelector; private readonly Func, Uri?> _authServerSelector; private readonly AuthorizationRedirectDelegate _authorizationRedirectDelegate; private readonly Uri? _clientMetadataDocumentUri; @@ -79,6 +80,9 @@ public ClientOAuthProvider( _additionalAuthorizationParameters = options.AdditionalAuthorizationParameters; _clientMetadataDocumentUri = options.ClientMetadataDocumentUri; + // Set up token endpoint authentication method selector (use default if not provided) + _tokenEndpointAuthMethodSelector = options.TokenEndpointAuthMethodSelector ?? DefaultTokenEndpointAuthMethodSelector; + // Set up authorization server selection strategy _authServerSelector = options.AuthServerSelector ?? DefaultAuthServerSelector; @@ -92,6 +96,13 @@ public ClientOAuthProvider( _tokenCache = options.TokenCache ?? new InMemoryTokenCache(); } + /// + /// Default token endpoint authentication method selector that selects the first supported method from the authorization server metadata. + /// + /// The list of supported token endpoint authentication methods. + /// The selected token endpoint authentication method, or null if none are available. + private static string? DefaultTokenEndpointAuthMethodSelector(IReadOnlyList? tokenEndpointAuthMethodsSupported) => tokenEndpointAuthMethodsSupported?.FirstOrDefault(); + /// /// Default authorization server selection strategy that selects the first available server. /// @@ -306,7 +317,7 @@ await _tokenCache.GetTokensAsync(cancellationToken).ConfigureAwait(false) is { R } // Determine the token endpoint auth method from server metadata if not already set by DCR. - _tokenEndpointAuthMethod ??= authServerMetadata.TokenEndpointAuthMethodsSupported?.FirstOrDefault(); + _tokenEndpointAuthMethod ??= _tokenEndpointAuthMethodSelector(authServerMetadata.TokenEndpointAuthMethodsSupported); // Store auth server metadata for future refresh operations _authServerMetadata = authServerMetadata;