Round #706

10 May 2026, 15:09· csharp· Meta-Llama-3.3-70B-Instruct· r13-clean-hints
Complexity
band 0
ZP / UO / OBS
5 / 5 / 0
Journey weight
621
Lightshift ΔL
+0.00

Prompt

Implement a custom AuthenticationHandler<TOptions> for a header-based API key, including ChallengeAsync and AuthenticateResult.

Zero-point index (what the engine surfaced)

ZPI-ZPI-0005 | 2026-05-10T15:09:29Z Implement a custom AuthenticationHandler<TOptions> for a header-based API key, including ChallengeAsync and AuthenticateResult. ZERO POINT — 5 entries (structural invariants) ● hsl(228.20, 100%, 30%) IAuthenticationHandler [contract] ● hsl(61.59, 100%, 30%) AuthenticationHandler<TOptions> [contract] ● hsl(257.20, 100%, 30%) AuthenticationSchemeOptions [contract] ● hsl(161.43, 100%, 30%) JwtBearerOptions [contract] ● hsl(89.40, 100%, 30%) OpenIdConnectOptions [contract] UNOBSERVED — 5 entries (implied truths) ○ hsl(27.69, 100%, 50%) async [feature] ○ hsl(9.23, 100%, 50%) interface [feature] ○ hsl(77.54, 100%, 42%) Routing middleware [function] ○ hsl(83.08, 100%, 42%) ILogger of T injection [function] ○ hsl(31.38, 100%, 42%) Scoped registration [function] OBSERVED — 0 entries (explicit in request) COMPLEXITY │ 10 entries │ spread: 74° │ band: LOW

Baseline response (no ZPI)

**Custom Authentication Handler for Header-Based API Key** =========================================================== Below is an example implementation of a custom `AuthenticationHandler<TOptions>` for a header-based API key in C#. ### ApiKeyAuthenticationHandler.cs ```csharp using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using System; using System.Security.Claims; using System.Text; using System.Threading.Tasks; public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions { public string HeaderName { get; set; } = "X-Api-Key"; public string ApiKey { get; set; } } public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions> { public ApiKeyAuthenticationHandler( IOptionsMonitor<ApiKeyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { } protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.TryGetValue(Options.HeaderName, out var apiKeyHeaderValues)) { return AuthenticateResult.NoResult(); } var providedApiKey = apiKeyHeaderValues.FirstOrDefault(); if (string.IsNullOrEmpty(providedApiKey) || providedApiKey != Options.ApiKey) { return AuthenticateResult.Fail("Invalid API key"); } var claims = new[] { new Claim(ClaimTypes.Name, "API Key") }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return AuthenticateResult.Success(ticket); } protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { Response.StatusCode = StatusCodes.Status401Unauthorized; await Response.WriteAsync("Unauthorized: Invalid API key"); } } ``` ### Startup.cs (or Program.cs in .NET 6 and later) ```csharp using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(options => { options.DefaultScheme = "ApiKey"; }) .AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>("ApiKey", _ => { }); services.Configure<ApiKeyAuthenticationOptions>(options => { options.ApiKey = "your_secret_api_key"; }); services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } ``` ### Example Usage To use this custom authentication handler, you can decorate your controllers or actions with the `[Authorize]` attribute. The `ApiKeyAuthenticationHandler` will automatically check for the presence and validity of the API key in the `X-Api-Key` header. ```csharp [Authorize] [ApiController] [Route("api/[controller]")] public class MyController : ControllerBase { [HttpGet] public IActionResult Get() { return Ok("Hello, authenticated user!"); } } ``` When making requests to this controller, you must include a valid API key in the `X-Api-Key` header. For example, using `curl`: ```bash curl -X GET \ http://localhost:5000/api/my \ -H 'X-Api-Key: your_secret_api_key' ``` Replace `your_secret_api_key` with the actual API key configured in your application.

Enhanced response (with ZPI)

```csharp using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Security.Claims; using System.Text; using System.Threading.Tasks; public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions { public string HeaderName { get; set; } = "X-Api-Key"; public string ApiKey { get; set; } } public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions> { private readonly ILogger _logger; public ApiKeyAuthenticationHandler( IOptionsMonitor<ApiKeyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { _logger = logger.CreateLogger<ApiKeyAuthenticationHandler>(); } protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.TryGetValue(Options.HeaderName, out var apiKeyHeaderValues)) { return AuthenticateResult.NoResult(); } var providedApiKey = apiKeyHeaderValues.FirstOrDefault(); if (string.IsNullOrEmpty(providedApiKey)) { return AuthenticateResult.NoResult(); } if (providedApiKey != Options.ApiKey) { _logger.LogWarning("Invalid API key provided."); return AuthenticateResult.Fail("Invalid API key"); } var claims = new[] { new Claim(ClaimTypes.Name, "API Key") }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return AuthenticateResult.Success(ticket); } protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { Response.StatusCode = 401; Response.Headers.Append("WWW-Authenticate", $"Bearer realm=\"{Options.HeaderName}\""); await base.HandleChallengeAsync(properties); } } public static class ApiKeyAuthenticationExtensions { public static AuthenticationBuilder AddApiKeyAuthentication( this AuthenticationBuilder builder, Action<ApiKeyAuthenticationOptions> configureOptions) { builder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>( "ApiKey", configureOptions); return builder; } } ``` This implementation provides a custom `AuthenticationHandler<TOptions>` for a header-based API key. The `ApiKeyAuthenticationOptions` class defines the configuration options for the authentication scheme, including the header name and the expected API key. The `ApiKeyAuthenticationHandler` class handles the authentication process. It checks for the presence of the API key header in the request and verifies its value against the expected API key. If the API key is valid, it creates a claims identity and returns an authentication ticket. The `HandleChallengeAsync` method is used to handle challenges, such as when an invalid API key is provided. It sets the response status code to 401 and includes a WWW-Authenticate header with the expected header name. The `ApiKeyAuthenticationExtensions` class provides an extension method for adding the API key authentication scheme to the authentication builder. To use this implementation, you can add the API key authentication scheme to the authentication builder in the `Startup.cs` file: ```csharp public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(options => { options.DefaultScheme = "ApiKey"; }) .AddApiKeyAuthentication(options => { options.HeaderName = "X-Api-Key"; options.ApiKey = "your_api_key_here"; }); } ``` You can then use the `[Authorize]` attribute to protect controllers or actions that require API key authentication.

Grader chain

Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.

V1samba/Meta-Llama-3.3-70B-Instruct
Better
V4qwen2.5-coder-3b-instruct
Better
V5openrouter/qwen/qwen3-235b-a22b-2507
Better
V7qwen2.5-coder-7b-instruct
Better
V8openai/gpt-4.1
Better
V9anthropic/claude-opus-4-7
Same
V12openai/gpt-4o
Better

Comments

Our grader said what it said. What do you say? Comment as a guest below.

No comments yet. Be the first to say what you make of this round.

← back to all rounds