Implement RFC 9207 issuer validation in ClientOAuthProvider (#1605)

This commit is contained in:
Mike Kistler 2026-07-23 08:01:22 -07:00 • committed by GitHub
commit 4aade88558
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -3,6 +3,7 @@ using System.Net.Sockets;
using System.Text.Json;
using System.Web;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Authentication;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
@ -92,7 +93,7 @@ var oauthOptions = new ModelContextProtocol.Authentication.ClientOAuthOptions
RedirectUri = clientRedirectUri,
// Configure the metadata document URI for CIMD.
ClientMetadataDocumentUri = new Uri("https://conformance-test.local/client-metadata.json"),
AuthorizationRedirectDelegate = (authUrl, redirectUri, ct) => HandleAuthorizationUrlAsync(authUrl, redirectUri, ct),
AuthorizationCallbackHandler = HandleAuthorizationUrlAsync,
};
if (preRegisteredClientId is not null)
@ -340,8 +341,12 @@ catch (Exception ex)
// Copied from ProtectedMcpClient sample
// Simulate a user opening the browser and logging in
// Copied from OAuthTestBase
static async Task<string?> HandleAuthorizationUrlAsync(Uri authorizationUrl, Uri redirectUri, CancellationToken cancellationToken)
static async Task<AuthorizationResult?> HandleAuthorizationUrlAsync(
AuthorizationCallbackContext authorizationContext,
CancellationToken cancellationToken)
{
var authorizationUrl = authorizationContext.AuthorizationUri;
Console.WriteLine("Starting OAuth authorization flow...");
Console.WriteLine($"Simulating opening browser to: {authorizationUrl}");
@ -355,16 +360,30 @@ static async Task<string?> HandleAuthorizationUrlAsync(Uri authorizationUrl, Uri
if (location is not null && !string.IsNullOrEmpty(location.Query))
{
// Parse query string to extract "code" parameter
// Parse query string to extract "code" and "iss" parameters
var query = location.Query.TrimStart('?');
string? code = null;
string? iss = null;
foreach (var pair in query.Split('&'))
{
var parts = pair.Split('=', 2);
if (parts.Length == 2 && parts[0] == "code")
if (parts.Length == 2)
{
return HttpUtility.UrlDecode(parts[1]);
if (parts[0] == "code")
{
code = HttpUtility.UrlDecode(parts[1]);
}
else if (parts[0] == "iss")
{
iss = HttpUtility.UrlDecode(parts[1]);
}
}
}
if (code is not null)
{
return new AuthorizationResult { Code = code, Iss = iss };
}
}
return null;