c4270a4975
The MCP endpoint handles its own authentication via X-Agent-Id and X-Nexus-Api-Key headers through NexusMcpTools. The ApiKeyMiddleware now skips the /mcp path to avoid interfering with MCP's own auth flow.
52 lines
1.8 KiB
C#
52 lines
1.8 KiB
C#
using System.Security.Claims;
|
|
|
|
namespace Nexus.Api.Middleware;
|
|
|
|
/// <summary>
|
|
/// Middleware that authenticates requests via the X-Nexus-Api-Key header.
|
|
/// On match, sets a ClaimsPrincipal with role "Service".
|
|
/// On mismatch or absent header, passes through to next middleware (JWT auth).
|
|
///
|
|
/// The MCP endpoint (/mcp) is intentionally skipped — the MCP SDK handles its own
|
|
/// authentication via X-Agent-Id + X-Nexus-Api-Key headers through NexusMcpTools.
|
|
/// </summary>
|
|
public sealed class ApiKeyMiddleware(RequestDelegate next)
|
|
{
|
|
private static readonly PathString McpPath = new("/mcp");
|
|
|
|
public async Task InvokeAsync(HttpContext context)
|
|
{
|
|
// MCP endpoint handles its own auth — skip ApiKey interference
|
|
if (context.Request.Path.StartsWithSegments(McpPath))
|
|
{
|
|
await next(context);
|
|
return;
|
|
}
|
|
|
|
var configuration = context.RequestServices.GetRequiredService<IConfiguration>();
|
|
var apiKey = configuration["NexusApiKey"];
|
|
|
|
if (!string.IsNullOrWhiteSpace(apiKey) &&
|
|
context.Request.Headers.TryGetValue("X-Nexus-Api-Key", out var providedKey) &&
|
|
string.Equals(apiKey, providedKey, StringComparison.Ordinal))
|
|
{
|
|
var claims = new[]
|
|
{
|
|
new Claim(ClaimTypes.NameIdentifier, "service"),
|
|
new Claim(ClaimTypes.Name, "ApiService"),
|
|
new Claim(ClaimTypes.Role, "Service")
|
|
};
|
|
var identity = new ClaimsIdentity(claims, "ApiKey");
|
|
context.User = new ClaimsPrincipal(identity);
|
|
}
|
|
|
|
await next(context);
|
|
}
|
|
}
|
|
|
|
public static class ApiKeyMiddlewareExtensions
|
|
{
|
|
public static IApplicationBuilder UseApiKeyAuthentication(this IApplicationBuilder builder)
|
|
=> builder.UseMiddleware<ApiKeyMiddleware>();
|
|
}
|