JWT authentication setup, token generation with claims, refresh token flow, and token validation configuration. Trigger: JWT, authentication, token, Bearer, claims, refresh token.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
JsonWebTokenHandler (.NET 10+) or JwtSecurityTokenHandler for token generation// Program.cs
builder.Services.AddAuthentication(
JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(
builder.Configuration["Jwt:Key"]!)),
ClockSkew = TimeSpan.FromSeconds(30) // default is 5 min
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
public sealed class JwtOptions
{
public const string SectionName = "Jwt";
[Required]
public required string Issuer { get; init; }
[Required]
public required string Audience { get; init; }
[Required, MinLength(32)]
public required string Key { get; init; }
[Range(1, 1440)]
public int AccessTokenExpiryMinutes { get; init; } = 60;
[Range(1, 43200)]
public int RefreshTokenExpiryMinutes { get; init; } = 10080; // 7 days
}
// Registration
builder.Services.AddOptions<JwtOptions>()
.BindConfiguration(JwtOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart();
public interface ITokenService
{
TokenResponse GenerateTokens(
User user, IEnumerable<string> permissions);
}
public sealed class TokenService(IOptions<JwtOptions> options)
: ITokenService
{
public TokenResponse GenerateTokens(
User user, IEnumerable<string> permissions)
{
var claims = new List<Claim>
{
new(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
new(JwtRegisteredClaimNames.Email, user.Email),
new(JwtRegisteredClaimNames.Jti,
Guid.NewGuid().ToString()),
new("permissions", string.Join(",", permissions))
};
foreach (var role in user.Roles)
claims.Add(new Claim(ClaimTypes.Role, role));
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(options.Value.Key));
var credentials = new SigningCredentials(
key, SecurityAlgorithms.HmacSha256);
var expiry = DateTime.UtcNow.AddMinutes(
options.Value.AccessTokenExpiryMinutes);
var token = new JwtSecurityToken(
issuer: options.Value.Issuer,
audience: options.Value.Audience,
claims: claims,
expires: expiry,
signingCredentials: credentials);
return new TokenResponse(
AccessToken: new JwtSecurityTokenHandler().WriteToken(token),
ExpiresAt: expiry,
RefreshToken: GenerateRefreshToken());
}
private static string GenerateRefreshToken()
=> Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
}
public sealed record TokenResponse(
string AccessToken,
DateTime ExpiresAt,
string RefreshToken);
public sealed record RefreshTokenCommand(
string RefreshToken) : IRequest<Result<TokenResponse>>;
internal sealed class RefreshTokenHandler(
ITokenService tokenService,
IRefreshTokenRepository refreshTokenRepo,
IUserRepository userRepo)
: IRequestHandler<RefreshTokenCommand, Result<TokenResponse>>
{
public async Task<Result<TokenResponse>> Handle(
RefreshTokenCommand request, CancellationToken ct)
{
var stored = await refreshTokenRepo
.FindByTokenAsync(request.RefreshToken, ct);
if (stored is null || stored.IsExpired || stored.IsRevoked)
return Result<TokenResponse>.Failure(
Error.Unauthorized("Token.Invalid",
"Invalid or expired refresh token"));
// Rotate: revoke old token
stored.Revoke();
var user = await userRepo.FindAsync(stored.UserId, ct);
var permissions = await userRepo
.GetPermissionsAsync(user!.Id, ct);
var newToken = tokenService.GenerateTokens(
user!, permissions);
// Store new refresh token
await refreshTokenRepo.StoreAsync(
new RefreshToken(user!.Id, newToken.RefreshToken,
DateTime.UtcNow.AddDays(7)),
ct);
await refreshTokenRepo.SaveChangesAsync(ct);
return Result<TokenResponse>.Success(newToken);
}
}
app.MapPost("/auth/login", async (
LoginRequest request,
ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(
new LoginCommand(request.Email, request.Password), ct);
return result.Match(
token => Results.Ok(token),
error => Results.Unauthorized());
});
app.MapPost("/auth/refresh", async (
RefreshTokenRequest request,
ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(
new RefreshTokenCommand(request.RefreshToken), ct);
return result.Match(
token => Results.Ok(token),
error => Results.Unauthorized());
});
public interface ICurrentUserService
{
Guid UserId { get; }
string Email { get; }
IReadOnlyList<string> Roles { get; }
IReadOnlyList<string> Permissions { get; }
}
internal sealed class CurrentUserService(
IHttpContextAccessor httpContextAccessor)
: ICurrentUserService
{
private ClaimsPrincipal User =>
httpContextAccessor.HttpContext?.User
?? throw new UnauthorizedAccessException();
public Guid UserId => Guid.Parse(
User.FindFirstValue(JwtRegisteredClaimNames.Sub)!);
public string Email =>
User.FindFirstValue(JwtRegisteredClaimNames.Email)!;
public IReadOnlyList<string> Roles =>
User.FindAll(ClaimTypes.Role)
.Select(c => c.Value).ToList();
public IReadOnlyList<string> Permissions =>
(User.FindFirstValue("permissions") ?? "")
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.ToList();
}
AddJwtBearer in Program.csJwtSecurityTokenHandler or JsonWebTokenHandler usageTokenValidationParameters configurationITokenService or similar abstraction[Authorize] attributes on controllers/endpointsValidateOnStart for JWT configurationICurrentUserService for claim access in handlers