Round #716
10 May 2026, 15:12· csharp· Meta-Llama-3.3-70B-Instruct· r13-clean-hints
- Complexity
- band 0
- ZP / UO / OBS
- 5 / 0 / 2
- Journey weight
- 447
- Lightshift ΔL
- +0.40
Prompt
Implement a JwtBearerOptions handler that validates a custom claim transformation using IClaimsTransformation in DI.
Zero-point index (what the engine surfaced)
ZPI-ZPI-0015 | 2026-05-10T15:12:28Z
Implement a JwtBearerOptions handler that validates a custom claim transformation using IClaimsTransformation in DI.
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 — 0 entries (implied truths)
OBSERVED — 2 entries (explicit in request)
◉ hsl(85.13, 100%, 50%) using [feature]
◉ hsl(234.87, 100%, 50%) using [feature]
COMPLEXITY │ 7 entries │ spread: 150° │ band: LOW
Baseline response (no ZPI)
**Custom Claim Transformation using IClaimsTransformation**
===========================================================
In this example, we will implement a custom claim transformation using `IClaimsTransformation` and validate it using `JwtBearerOptions` in a .NET Core application.
**IClaimsTransformation Implementation**
--------------------------------------
First, let's create a custom implementation of `IClaimsTransformation` that adds a custom claim to the principal:
```csharp
using Microsoft.AspNetCore.Authentication;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
public class CustomClaimsTransformation : IClaimsTransformation
{
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var claims = principal.Claims.ToList();
// Add a custom claim
claims.Add(new Claim("custom_claim", "custom_value"));
var newIdentity = new ClaimsIdentity(claims, principal.Identity.AuthenticationType);
var newPrincipal = new ClaimsPrincipal(newIdentity);
return newPrincipal;
}
}
```
**JwtBearerOptions Configuration**
---------------------------------
Next, let's configure `JwtBearerOptions` to use our custom claim transformation:
```csharp
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Audience = "your_audience";
options.Authority = "your_authority";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_secret_key"))
};
// Use our custom claim transformation
options.Events = new JwtBearerEvents
{
OnTokenValidated = async context =>
{
var claimsTransformation = context.HttpContext.RequestServices.GetService<IClaimsTransformation>();
var newPrincipal = await claimsTransformation.TransformAsync(context.Principal);
context.Principal = newPrincipal;
}
};
});
// Register our custom claim transformation
services.AddTransient<IClaimsTransformation, CustomClaimsTransformation>();
}
```
**Example Usage**
-----------------
To test our custom claim transformation, we can create a simple controller that returns the claims of the authenticated user:
```csharp
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
[ApiController]
[Route("api/[controller]")]
public class ClaimsController : ControllerBase
{
[Authorize]
[HttpGet]
public IActionResult GetClaims()
{
var claims = User.Claims.ToList();
return Ok(claims);
}
}
```
When we make a GET request to `/api/claims`, we should see the custom claim `custom_claim` with value `custom_value` in the response.
**Full Code Example**
---------------------
Here is the full code example:
```csharp
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace CustomClaimTransformationExample
{
public class CustomClaimsTransformation : IClaimsTransformation
{
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var claims = principal.Claims.ToList();
// Add a custom claim
claims.Add(new Claim("custom_claim", "custom_value"));
var newIdentity = new ClaimsIdentity(claims, principal.Identity.AuthenticationType);
var newPrincipal = new ClaimsPrincipal(newIdentity);
return newPrincipal;
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Audience = "your_audience";
options.Authority = "your_authority";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_secret_key"))
};
// Use our custom claim transformation
options.Events = new JwtBearerEvents
{
OnTokenValidated = async context =>
{
var claimsTransformation = context.HttpContext.RequestServices.GetService<IClaimsTransformation>();
var newPrincipal = await claimsTransformation.TransformAsync(context.Principal);
context.Principal = newPrincipal;
}
};
});
// Register our custom claim transformation
services.AddTransient<IClaimsTransformation, CustomClaimsTransformation>();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
[ApiController]
[Route("api/[controller]")]
public class ClaimsController : ControllerBase
{
[Authorize]
[HttpGet]
public IActionResult GetClaims()
{
var claims = User.Claims.ToList();
return Ok(claims);
}
}
}
```
Note that you should replace `your_audience`, `your_authority`, and `your_secret_key` with your actual JWT settings.
Enhanced response (with ZPI)
```csharp
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
// Custom claim transformation
public class CustomClaimsTransformation : IClaimsTransformation
{
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var claims = principal.Claims.ToList();
// Custom claim transformation logic
var customClaim = new Claim("custom_claim", "custom_value");
claims.Add(customClaim);
var newIdentity = new ClaimsIdentity(claims, principal.Identity.AuthenticationType);
var newPrincipal = new ClaimsPrincipal(newIdentity);
return await Task.FromResult(newPrincipal);
}
}
// JwtBearerOptions handler with custom claim transformation
public class CustomJwtBearerOptionsHandler : AuthenticationHandler<JwtBearerOptions>
{
private readonly IClaimsTransformation _claimsTransformation;
public CustomJwtBearerOptionsHandler(
IOptionsMonitor<JwtBearerOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
IClaimsTransformation claimsTransformation)
: base(options, logger, encoder, clock)
{
_claimsTransformation = claimsTransformation;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var authenticateResult = await base.HandleAuthenticateAsync();
if (authenticateResult.Succeeded)
{
var transformedPrincipal = await _claimsTransformation.TransformAsync(authenticateResult.Principal);
return AuthenticateResult.Success(new AuthenticationTicket(transformedPrincipal, authenticateResult.Properties, Scheme.Name));
}
return authenticateResult;
}
}
// DI registration
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IClaimsTransformation, CustomClaimsTransformation>();
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Audience = "your_audience";
options.Authority = "your_authority";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey("your_secret_key".Sha256())
};
});
services.AddSingleton<AuthenticationHandler<JwtBearerOptions>, CustomJwtBearerOptionsHandler>();
}
```
This implementation provides a custom `IClaimsTransformation` that adds a custom claim to the principal. The `CustomJwtBearerOptionsHandler` class inherits from `AuthenticationHandler<JwtBearerOptions>` and overrides the `HandleAuthenticateAsync` method to apply the custom claim transformation after successful authentication. The `CustomClaimsTransformation` and `CustomJwtBearerOptionsHandler` are registered in the DI container in the `ConfigureServices` method.
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
BetterV4qwen2.5-coder-3b-instruct
BetterV5openrouter/qwen/qwen3-235b-a22b-2507
BetterV7qwen2.5-coder-7b-instruct
BetterV8openai/gpt-4.1
WorseV9anthropic/claude-opus-4-7
WorseV12openai/gpt-4o
BetterComments
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.