-
Notifications
You must be signed in to change notification settings - Fork 253
WIP: Authorization Support (Using ASP.NET Core Native AuthN/AuthZ Integration) #377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationExtensions.cs
Outdated
Show resolved
Hide resolved
src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationExtensions.cs
Outdated
Show resolved
Hide resolved
src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationExtensions.cs
Outdated
Show resolved
Hide resolved
src/ModelContextProtocol.AspNetCore/Auth/McpAuthenticationResponseMiddlewareExtensions.cs
Outdated
Show resolved
Hide resolved
// Add authorization policy for MCP | ||
builder.Services.AddAuthorization(options => | ||
{ | ||
options.AddPolicy("McpAuth", policy => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be where an AddMcpPolicy would be handy. It could preconfigure RequireAuthenticatedUser and AddAuthenticationSchemes(McpAuthenticationDefaults.AuthenticationScheme) and then give the policy builder to your callback for further customization.
Co-authored-by: Stephen Halter <[email protected]>
Co-authored-by: Stephen Halter <[email protected]>
…sions.cs Co-authored-by: Stephen Halter <[email protected]>
src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationExtensions.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Stephen Halter <[email protected]>
…sions.cs Co-authored-by: Stephen Halter <[email protected]>
…sions.cs Co-authored-by: Stephen Halter <[email protected]>
src/ModelContextProtocol.AspNetCore/Auth/McpAuthenticationHandler.cs
Outdated
Show resolved
Hide resolved
src/ModelContextProtocol.AspNetCore/Auth/McpAuthenticationHandler.cs
Outdated
Show resolved
Hide resolved
// Set up the resource URI if not already configured, using the current request as a fallback | ||
if (Options.ResourceMetadata.Resource == null) | ||
{ | ||
Options.ResourceMetadata.Resource = new Uri($"{Request.Scheme}://{Request.Host}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assumes the server is hosted at the root of the domain, which is not always the case. It may also need {Request.PathBase} or something similar
|
||
// Set the WWW-Authenticate header with the resource_metadata | ||
string headerValue = $"Bearer realm=\"{Scheme.Name}\""; | ||
headerValue += $", resource_metadata=\"{metadataUrl}\""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the metadata url needs to be escaped
resource_metadata=\"{Uri.EscapeDataString(metadataUri.ToString())}\"
/// This contains the OAuth metadata for the protected resource, including authorization servers, | ||
/// supported scopes, and other information needed for clients to authenticate. | ||
/// </remarks> | ||
public ProtectedResourceMetadata ResourceMetadata { get; set; } = new ProtectedResourceMetadata(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be an option to return this dynamically so that the metadata can change based upon incoming callers.
config.Scopes); | ||
|
||
// Attach the access token to future requests | ||
httpClient.AttachToken(tokenResponse.AccessToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this may not handle token expiry and refresh, as in the token could expire and get stuck on the http client instance, never succeeding after expiration.
/// </summary> | ||
public static class OAuthAuthorizationHelpers | ||
{ | ||
private static readonly HttpClient _httpClient = new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can lead to outages. IHttpClientFactory needs to be used to follow best practices. Sockets sometimes get into a bad state and need to be recycled. That's why periodic recycling is handled by the http client factory internally.
/// <summary> | ||
/// Provides helper methods for handling OAuth authorization. | ||
/// </summary> | ||
public static class OAuthAuthorizationHelpers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be turned into an instance type with an interface, registered as a singleton so that its implementation can be replaced by more secure and/or custom ones.
{ | ||
// Create a temporary HttpClient to handle the authentication | ||
// We need to use a new client to avoid infinite recursion | ||
using var httpClient = new HttpClient(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a new http client should not be created within a delegating handler. Use base.SendAsync to make other network calls.
Implements the authorization flow for clients and servers, per specification. Instead of re-implementing everything from scratch, this follows the suggestions from #349 and uses the native ASP.NET Core constructs to handle post-discovery steps server-side.