diff --git a/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs b/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs index df1c44c1f..16df4816c 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthOptions.cs @@ -113,6 +113,20 @@ public sealed class ClientOAuthOptions UrlFormat = ModelContextProtocol.Obsoletions.AuthorizationRedirectDelegate_Url)] 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 785e3cc2e..07e13552e 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs @@ -30,6 +30,7 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient private readonly string? _configuredScopes; private readonly ScopeSelectorDelegate? _scopeSelector; private readonly IDictionary _additionalAuthorizationParameters; + private readonly Func?, string?> _tokenEndpointAuthMethodSelector; private readonly Func, Uri?> _authServerSelector; private readonly Func> _authorizationCallbackHandler; private readonly bool _validateAuthorizationResponseState; @@ -106,6 +107,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; @@ -154,6 +158,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. /// @@ -475,7 +486,7 @@ private async Task GetAccessTokenCoreAsync(HttpResponseMessage response, _clientCredentialsAuthorizationServer = selectedAuthServer.OriginalString; // 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;