Round #482
09 May 2026, 19:39· csharp· qwen2.5-coder-7b-instruct· r13-clean-hints
- Complexity
- band 1
- ZP / UO / OBS
- 5 / 8 / 0
- Journey weight
- 840
- Lightshift ΔL
- +0.50
Prompt
Write a refresh token rotation endpoint that invalidates old tokens
Zero-point index (what the engine surfaced)
ZPI-ZPI-0006 | 2026-05-09T19:39:09Z
Write a refresh token rotation endpoint that invalidates old tokens
ZERO POINT — 5 entries (structural invariants)
● hsl(228.20, 100%, 22%) IAuthenticationHandler [contract]
● hsl(61.59, 100%, 22%) AuthenticationHandler<TOptions> [contract]
● hsl(257.20, 100%, 22%) AuthenticationSchemeOptions [contract]
● hsl(161.43, 100%, 22%) JwtBearerOptions [contract]
● hsl(89.40, 100%, 22%) OpenIdConnectOptions [contract]
UNOBSERVED — 8 entries (implied truths)
○ hsl(27.69, 100%, 50%) async [feature]
○ hsl(49.23, 100%, 50%) try [feature]
○ hsl(112.62, 100%, 30%) Token validation parameters [function]
○ hsl(31.38, 100%, 42%) Scoped registration [function]
○ hsl(44.31, 100%, 42%) IOptions of T binding [function]
○ 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]
OBSERVED — 0 entries (explicit in request)
COMPLEXITY │ 13 entries │ spread: 103° │ band: MEDIUM
Baseline response (no ZPI)
Certainly! Below is an example of a refresh token rotation endpoint in C# using ASP.NET Core. This endpoint will invalidate old refresh tokens and issue new ones.
First, ensure you have the necessary packages installed:
- `Microsoft.AspNetCore.Authentication.JwtBearer`
- `Microsoft.IdentityModel.Tokens`
Here's a complete example:
1. **Startup.cs** or **Program.cs** (depending on your project structure):
```csharp
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.Text;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// Configure JWT Authentication
var key = Encoding.ASCII.GetBytes("your_secret_key_here");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
};
});
// Configure in-memory store for refresh tokens
services.AddSingleton<IRefreshTokenStore, InMemoryRefreshTokenStore>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
```
2. **InMemoryRefreshTokenStore.cs**:
```csharp
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class InMemoryRefreshTokenStore : IRefreshTokenStore
{
private readonly ConcurrentDictionary<string, string> _refreshTokens = new ConcurrentDictionary<string, string>();
public Task AddAsync(string token)
{
return _refreshTokens.TryAdd(token, token);
}
public Task RemoveAsync(string token)
{
return _refreshTokens.TryRemove(token, out _);
}
public Task<bool> ContainsAsync(string token)
{
return _refreshTokens.ContainsKeyAsync(token);
}
}
```
3. **IRefreshTokenStore.cs**:
```csharp
public interface IRefreshTokenStore
{
Task AddAsync(string token);
Task RemoveAsync(string token);
Task<bool> ContainsAsync(string token);
}
```
4. **RefreshTokenController.cs**:
```csharp
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
[Route("api/[controller]")]
[ApiController]
public class RefreshTokenController : ControllerBase
{
private readonly IRefreshTokenStore _refreshTokenStore;
private readonly string _secretKey;
public RefreshTokenController(IRefreshTokenStore refreshTokenStore, IConfiguration configuration)
{
_refreshTokenStore = refreshTokenStore;
_secretKey = configuration["Jwt:Secret"];
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] RefreshTokenRequest request)
{
if (!await _refreshTokenStore.ContainsAsync(request.Token))
{
return Unauthorized("Invalid refresh token");
}
// Invalidate the old token
await _refreshTokenStore.RemoveAsync(request.Token);
// Generate a new access token and refresh token
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, "user_id"),
new Claim(ClaimTypes.Email, "user@example.com")
};
var key = Encoding.ASCII.GetBytes(_secretKey);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddHours(1), // Access token expires in 1 hour
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var accessToken = new JwtSecurityTokenHandler().CreateToken(tokenDescriptor);
var newAccessToken = new JwtSecurityTokenHandler().WriteToken(accessToken);
var refreshToken = Guid.NewGuid().ToString();
await _refreshTokenStore.AddAsync(refreshToken);
return Ok(new
{
AccessToken = newAccessToken,
RefreshToken = refreshToken
});
}
}
public class RefreshTokenRequest
{
public string Token { get; set; }
}
```
### Explanation:
1. **Startup.cs**: Configures JWT authentication and adds an in-memory store for refresh tokens.
2. **InMemoryRefreshTokenStore.cs**: A simple in-memory implementation of the `IRefreshTokenStore` interface to store and manage refresh tokens.
3. **IRefreshTokenStore.cs**: Defines the contract for a refresh token store.
4. **RefreshTokenController.cs**: Handles the refresh token rotation endpoint. It invalidates old tokens, generates new access and refresh tokens, and returns them.
### Usage:
- The client sends a POST request to `/api/refresh-token` with the old refresh token in the body.
- The server validates the old token, invalidates it, and issues new access and refresh tokens.
- The client then uses the new access token for subsequent requests.
This example provides a basic implementation. Depending on your requirements, you may need to add additional features such as token expiration handling, user-specific refresh token storage, and more secure key management.
Enhanced response (with ZPI)
To implement a refresh token rotation endpoint that invalidates old tokens, we'll use the `IAuthenticationHandler` and related types to handle authentication and token validation. We'll also use dependency injection (DI) for better testability and maintainability.
Here's the complete implementation:
1. **Create a custom authentication handler**:
This handler will be responsible for validating refresh tokens and issuing new access tokens.
2. **Configure the authentication scheme**:
Register the custom authentication handler with the DI container.
3. **Create a controller to handle token rotation**:
This controller will expose an endpoint that invalidates old tokens and issues new ones.
### Step 1: Create a Custom Authentication Handler
```csharp
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using System.Threading.Tasks;
public class RefreshTokenHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly ILogger<RefreshTokenHandler> _logger;
public RefreshTokenHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
_logger = logger;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var token = Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
if (string.IsNullOrEmpty(token))
{
return AuthenticateResult.NoResult();
}
// Validate the refresh token and issue a new access token
try
{
var claims = ValidateToken(token);
var identity = new ClaimsIdentity(claims, Scheme.Name);
var ticket = new AuthenticationTicket(identity, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to authenticate refresh token");
return AuthenticateResult.Fail("Invalid token");
}
}
private IEnumerable<Claim> ValidateToken(string token)
{
// Implement your token validation logic here
// For example, check if the token is valid and not expired
// Return the claims from the token
throw new NotImplementedException();
}
}
```
### Step 2: Configure the Authentication Scheme
```csharp
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
public static class AuthExtensions
{
public static IServiceCollection AddRefreshTokenAuth(this IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "RefreshToken";
options.DefaultChallengeScheme = "RefreshToken";
})
.AddScheme<AuthenticationSchemeOptions, RefreshTokenHandler>("RefreshToken", options => { });
return services;
}
}
```
### Step 3: Create a Controller to Handle Token Rotation
```csharp
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly IAuthenticationService _authenticationService;
public AuthController(IAuthenticationService authenticationService)
{
_authenticationService = authenticationService;
}
[HttpPost("refresh")]
[Authorize(AuthenticationSchemes = "RefreshToken")]
public async Task<IActionResult> RefreshToken()
{
var user = User.Identity as ClaimsIdentity;
if (user == null || !user.HasClaim(c => c.Type == ClaimTypes.NameIdentifier))
{
return Unauthorized();
}
var userId = user.FindFirst(ClaimTypes.NameIdentifier).Value;
// Invalidate old tokens and issue new ones
var result = await _authenticationService.SignInAsync(userId, "RefreshToken");
if (result.Succeeded)
{
return Ok(new { token = result.Token });
}
return Unauthorized();
}
}
```
### Explanation
1. **Custom Authentication Handler (`RefreshTokenHandler`)**:
- This handler is responsible for validating refresh tokens and issuing new access tokens.
- It checks the `Authorization` header for a refresh token, validates it, and returns a new authentication ticket if valid.
2. **Authentication Scheme Configuration**:
- The `AddRefreshTokenAuth` extension method registers the custom authentication handler with the DI container.
- It sets the default authenticate and challenge schemes to "RefreshToken".
3. **Controller (`AuthController`)**:
- This controller exposes an endpoint `/api/auth/refresh` that handles token rotation.
- It uses the `[Authorize]` attribute to ensure only authenticated requests can access this endpoint.
- The `SignInAsync` method is used to invalidate old tokens and issue new ones.
This implementation provides a robust solution for handling refresh token rotation, ensuring that old tokens are invalidated and new ones are issued securely.
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
WorseV7qwen2.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.