Skip to content

Commit 3852be9

Browse files
committed
Cleaner implementation
1 parent 31f611a commit 3852be9

File tree

3 files changed

+28
-98
lines changed

3 files changed

+28
-98
lines changed

samples/ProtectedMCPServer/Program.cs

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414

1515
builder.Services.AddAuthentication(options =>
1616
{
17-
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
1817
options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme;
18+
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
1919
})
2020
.AddJwtBearer(options =>
2121
{
@@ -51,10 +51,6 @@
5151
OnChallenge = context =>
5252
{
5353
Console.WriteLine($"Challenging client to authenticate with Entra ID");
54-
55-
// Skip the default Bearer header - MCP handler will provide the complete one
56-
context.HandleResponse();
57-
5854
return Task.CompletedTask;
5955
}
6056
};
@@ -76,41 +72,9 @@
7672

7773
return metadata;
7874
};
79-
80-
// Specify authentication schemes that this server supports
81-
options.SupportedAuthenticationSchemes.Add("Bearer");
82-
options.SupportedAuthenticationSchemes.Add("Basic");
83-
84-
// For a server that doesn't want to support Bearer, you would simply not add it:
85-
// options.SupportedAuthenticationSchemes.Add("Basic");
86-
// options.SupportedAuthenticationSchemes.Add("Digest");
87-
88-
// You can also use the dynamic provider for more flexible scheme selection:
89-
/*
90-
options.SupportedAuthenticationSchemesProvider = context =>
91-
{
92-
// You can use context information to determine which schemes to offer
93-
var schemes = new List<string>();
94-
95-
// Add Bearer for most clients
96-
schemes.Add("Bearer");
97-
98-
// Example of conditional scheme based on client type or other factors
99-
if (context.Request.Headers.UserAgent.ToString().Contains("SpecialClient"))
100-
{
101-
schemes.Add("Basic");
102-
}
103-
104-
return schemes;
105-
};
106-
*/
10775
});
10876

109-
builder.Services.AddAuthorization(options =>
110-
{
111-
options.AddMcpPolicy(configurePolicy: builder =>
112-
builder.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme));
113-
});
77+
builder.Services.AddAuthorization();
11478

11579
builder.Services.AddHttpContextAccessor();
11680
builder.Services.AddMcpServer()
@@ -129,7 +93,8 @@
12993
app.UseAuthentication();
13094
app.UseAuthorization();
13195

132-
app.MapMcp().RequireAuthorization(McpAuthenticationDefaults.AuthenticationScheme);
96+
// Use the default MCP policy name that we've configured
97+
app.MapMcp().RequireAuthorization();
13398

13499
Console.WriteLine($"Starting MCP server with authorization at {serverUrl}");
135100
Console.WriteLine($"PRM Document URL: {serverUrl}.well-known/oauth-protected-resource");

src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationHandler.cs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,19 @@ private async Task HandleResourceMetadataRequestAsync()
113113
}
114114

115115
/// <inheritdoc />
116-
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
116+
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
117117
{
118-
// This handler doesn't perform authentication - it only adds resource metadata to challenges
119-
// The actual authentication will be handled by the bearer token handler or other authentication handlers
120-
return Task.FromResult(AuthenticateResult.NoResult());
118+
// If ForwardAuthenticate is set, forward the authentication to the specified scheme
119+
if (!string.IsNullOrEmpty(Options.ForwardAuthenticate) &&
120+
Options.ForwardAuthenticate != Scheme.Name)
121+
{
122+
// Simply forward the authentication request to the specified scheme and return its result
123+
// This ensures we don't interfere with the authentication process
124+
return await Context.AuthenticateAsync(Options.ForwardAuthenticate);
125+
}
126+
127+
// If no forwarding is configured, this handler doesn't perform authentication
128+
return AuthenticateResult.NoResult();
121129
}
122130

123131
/// <inheritdoc />
@@ -135,24 +143,9 @@ protected override Task HandleChallengeAsync(AuthenticationProperties properties
135143
// Store the resource_metadata in properties in case other handlers need it
136144
properties.Items["resource_metadata"] = rawPrmDocumentUri;
137145

138-
// Get supported schemes from the options
139-
var options = _optionsMonitor.CurrentValue;
140-
var supportedSchemes = options.GetSupportedAuthenticationSchemes(Request.HttpContext).ToList();
141-
142-
// If no schemes are explicitly defined, don't add any WWW-Authenticate headers
143-
if (supportedSchemes.Count == 0)
144-
{
145-
return base.HandleChallengeAsync(properties);
146-
}
147-
148-
// Add headers for each supported authentication scheme
149-
foreach (var scheme in supportedSchemes)
150-
{
151-
// For all schemes, include the realm and resource metadata
152-
// This allows discovery of OAuth capabilities regardless of the authentication scheme
153-
string headerValue = $"{scheme} realm=\"{Scheme.Name}\", resource_metadata=\"{rawPrmDocumentUri}\"";
154-
Response.Headers.Append("WWW-Authenticate", headerValue);
155-
}
146+
// Add the WWW-Authenticate header with Bearer scheme and resource metadata
147+
string headerValue = $"Bearer realm=\"{Scheme.Name}\", resource_metadata=\"{rawPrmDocumentUri}\"";
148+
Response.Headers.Append("WWW-Authenticate", headerValue);
156149

157150
return base.HandleChallengeAsync(properties);
158151
}

src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationOptions.cs

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,19 @@ public class McpAuthenticationOptions : AuthenticationSchemeOptions
2020
set { base.Events = value; }
2121
}
2222

23+
/// <summary>
24+
/// Gets or sets the scheme to use for forward authentication.
25+
/// </summary>
26+
/// <remarks>
27+
/// This is currently set as a constant to avoid adding a package dependency.
28+
/// </remarks>
29+
public new string ForwardAuthenticate { get; set; } = "Bearer";
30+
2331
/// <summary>
2432
/// The URI to the resource metadata document.
2533
/// </summary>
2634
/// <remarks>
27-
/// This URI will be included in the WWW-Authenticate header when a 401 response is returned
28-
/// and Bearer authentication is supported.
35+
/// This URI will be included in the WWW-Authenticate header when a 401 response is returned.
2936
/// </remarks>
3037
public Uri ResourceMetadataUri { get; set; } = DefaultResourceMetadataUri;
3138

@@ -49,26 +56,6 @@ public class McpAuthenticationOptions : AuthenticationSchemeOptions
4956
/// </remarks>
5057
public Func<HttpContext, ProtectedResourceMetadata>? ResourceMetadataProvider { get; set; }
5158

52-
/// <summary>
53-
/// Gets or sets the authentication schemes supported by this server.
54-
/// </summary>
55-
/// <remarks>
56-
/// When set, these schemes will be included in WWW-Authenticate headers during an authentication challenge.
57-
/// By default, this is empty and must be populated with the authentication schemes your server supports.
58-
/// If Bearer is included, the resource metadata URI will be included in its parameters.
59-
/// </remarks>
60-
public List<string> SupportedAuthenticationSchemes { get; set; } = new List<string>();
61-
62-
/// <summary>
63-
/// Gets or sets a delegate that dynamically provides authentication schemes based on the HTTP context.
64-
/// </summary>
65-
/// <remarks>
66-
/// When set, this delegate will be called to determine which authentication schemes to include
67-
/// in WWW-Authenticate headers during an authentication challenge. This takes precedence over the static
68-
/// <see cref="SupportedAuthenticationSchemes"/> property.
69-
/// </remarks>
70-
public Func<HttpContext, IEnumerable<string>>? SupportedAuthenticationSchemesProvider { get; set; }
71-
7259
/// <summary>
7360
/// Gets the resource metadata for the current request.
7461
/// </summary>
@@ -83,19 +70,4 @@ internal ProtectedResourceMetadata GetResourceMetadata(HttpContext context)
8370

8471
return ResourceMetadata;
8572
}
86-
87-
/// <summary>
88-
/// Gets the supported authentication schemes for the current request.
89-
/// </summary>
90-
/// <param name="context">The HTTP context for the current request.</param>
91-
/// <returns>The authentication schemes supported for the current request.</returns>
92-
internal IEnumerable<string> GetSupportedAuthenticationSchemes(HttpContext context)
93-
{
94-
if (SupportedAuthenticationSchemesProvider != null)
95-
{
96-
return SupportedAuthenticationSchemesProvider(context);
97-
}
98-
99-
return SupportedAuthenticationSchemes;
100-
}
10173
}

0 commit comments

Comments
 (0)