using System.Security.Claims; namespace Nexus.Api.Middleware; /// /// 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. /// 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(); 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(); }