A production-ready JWT authentication and token lifecycle engine for .NET, designed for security, scalability, and real-world distributed systems.
Unlike traditional JWT setups that rely on static secrets and stateless validation only, this package introduces a full token security lifecycle system with:
- Key rotation
- Multi-key validation (zero-downtime rotation)
- Refresh token lifecycle management
- Token revocation (blacklisting)
- Replay attack detection
- Session control per user/device
New version: 10.0.5 is available with updates to address rotatable keys and validation for the Key.
IMPORTANT: Version 10.0.0 will be deprecated, please use version 10.0.5
- Generate Access + Refresh token pairs
- Claims-based identity support
- Token decoding utilities
- Secure refresh token rotation
- Per-user session limits
- Token revocation (single or all sessions)
- Device-aware session tracking
- Replay attack detection (JTI tracking)
- Token blacklisting
- Hash-based refresh token storage
- Per-user active session enforcement
- Automatic key generation (if not provided)
- Rotating signing keys with KeyId (kid)
- Multi-key validation for backward compatibility
- Retains old keys until refresh-token expiry window ends
- Zero-downtime key rotation
Client → JWT Middleware → JwtService → Controller
Key rotation ensures all valid keys remain usable during rotation windows.
dotnet add package JwtServicePackageAdd to appsettings.json:
{
"JwtSettings": {
"SecretKey": "your-initial-secret-key-32chars-minimum",
"Issuer": "your-app",
"Audience": "your-app-users",
"AccessTokenExpiryMinutes": 15,
"RefreshTokenExpiryDays": 7,
"EnableKeyRotation": true,
"KeyRotationIntervalDays": 7,
"EnableTokenReplayDetection": true,
"EnableTokenBlacklisting": true,
"MaxActiveTokensPerUser": 5
}
}builder.Services.AddJwtAuthentication(builder.Configuration);
builder.Services.AddHttpContextAccessor();app.UseAuthentication();
app.UseAuthorization();Generate tokens:
var tokens = _jwtService.GenerateTokenPair("user-123");
Validate:
var result = _jwtService.ValidateAccessToken(token);
Refresh:
var newTokens = _jwtService.RefreshToken(refreshToken);var tokens = _jwtService.GenerateTokenPair(
userId: user.UserId.ToString(),
customClaims: new Dictionary<string, object>
{
{ ClaimTypes.Email, user.Email }
},
deviceInfo: "web",
ipAddress: "127.0.0.1"
);var result = _jwtService.ValidateAccessToken(token);
if (!result.IsValid)
{
// handle invalid token
}var newTokens = _jwtService.RefreshToken(refreshToken);_jwtService.RevokeToken(accessToken);
_jwtService.RevokeRefreshToken(refreshToken);
_jwtService.RevokeAllUserTokens(userId);Use claims via HttpContext:
var userId = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;JWT Middleware → cryptographic validation
JwtService → business security rules
Do NOT duplicate validation logic.
Token cleanup runs automatically via BackgroundService:
- Removes expired refresh tokens
- Clears old revoked tokens
- Cleans replay tracking
MIT License - free for commercial and personal use.
Created and Maintained by: Ethern-Myth