Jwt signing and encryption utilities
$ dotnet add package Plinth.Security.JwtJWT signing and encryption utilities, add-on to Plinth.Security
Provides utilities for creating, validating, and refreshing JWTs with support for both signed (JWS) and encrypted (JWE) tokens.
dotnet add package Plinth.Security.Jwt
Create and configure JwtGenerationOptions with your desired security mode:
using Plinth.Security.Jwt;
// Example using HMAC signature (symmetric key)
var secretKey = new byte[32]; // 32 bytes = 256 bits for HS256
// ... populate secretKey from secure configuration ...
var jwtOptions = new JwtGenerationOptions
{
SecurityMode = new JwtSecurityModeHmacSignature(secretKey),
Issuer = "MyApplication",
Audience = "MyApplicationUsers",
TokenLifetime = TimeSpan.FromMinutes(15),
MaxTokenLifetime = TimeSpan.FromHours(24),
TokenContentLogging = false // Set to true only in development
};
jwtOptions.Validate();
services.AddSingleton(jwtOptions);
services.AddSingleton<JwtValidator>();
services.AddSingleton<JwtGenerator>();
Use JwtGenerator to create tokens for authenticated users:
public class AuthController : Controller
{
private readonly JwtGenerator _jwtGenerator;
public AuthController(JwtGenerator jwtGenerator)
{
_jwtGenerator = jwtGenerator;
}
[HttpPost("login")]
public async Task<ActionResult> Login([FromBody] LoginRequest request)
{
// ... validate credentials ...
var userId = Guid.NewGuid(); // from your user database
var userName = "user@example.com";
var roles = new[] { "User", "Admin" };
// Create a JWT with basic user information
var jwtData = _jwtGenerator.GetBuilder(userId, userName, roles)
.Build();
return Ok(new { token = jwtData.Token });
}
}
You can add custom claims to the JWT:
var jwtData = _jwtGenerator.GetBuilder(userId, userName, roles)
.AddClaim("department", "Engineering")
.AddClaim("employee_id", "12345")
.Build();
Use JwtValidator to validate and extract claims from tokens:
public class SecureController : Controller
{
private readonly JwtValidator _jwtValidator;
public SecureController(JwtValidator jwtValidator)
{
_jwtValidator = jwtValidator;
}
[HttpGet("secure-data")]
public ActionResult GetSecureData([FromHeader(Name = "Authorization")] string authHeader)
{
try
{
var token = authHeader.Replace("Bearer ", "");
var claimsPrincipal = _jwtValidator.Validate(token);
var userId = claimsPrincipal.JwtUserId();
var userName = claimsPrincipal.JwtUserName();
var roles = claimsPrincipal.JwtRoles();
// ... use claims to authorize and fetch data ...
return Ok();
}
catch (SecurityTokenException ex)
{
return Unauthorized(new { error = "Invalid token" });
}
}
}
Refresh an existing token to extend its lifetime (up to MaxTokenLifetime):
[HttpPost("refresh")]
public ActionResult RefreshToken([FromBody] RefreshRequest request)
{
try
{
var newJwtData = _jwtGenerator.Refresh(request.Token);
return Ok(new { token = newJwtData.Token });
}
catch (SecurityTokenExpiredException)
{
return Unauthorized(new { error = "Token has reached maximum lifetime" });
}
}
Use for single-server or shared-secret scenarios:
var secretKey = new byte[32]; // 32 bytes for HS256, 48 for HS384, 64 for HS512
// Load from secure configuration (e.g., Azure Key Vault, environment variable)
var securityMode = new JwtSecurityModeHmacSignature(secretKey);
Use for distributed systems where token validation occurs on different servers:
using System.Security.Cryptography;
var rsa = RSA.Create(2048); // 2048-bit key
// Or load from certificate store
var securityMode = new JwtSecurityModeRsaSignature(rsa, SecurityAlgorithms.RsaSha256);
Use when token contents must be encrypted:
var encryptionKey = new byte[32]; // 32 bytes for AES256
// Load from secure configuration
var securityMode = new JwtSecurityModeAesEncryption(encryptionKey);
Use for encrypted tokens in distributed systems:
var rsa = RSA.Create(2048);
// Or load from certificate store
var securityMode = new JwtSecurityModeRsaEncryption(rsa);
The library provides extension methods for extracting JWT claims:
JwtUserId() - Get the user's unique identifier (Guid)JwtUserName() - Get the user's unique name/emailJwtRoles() - Get the user's roles as an arrayJwtSessionGuid() - Get the session identifierJwtOriginalIssue() - Get the original issue date (for refresh tracking)TokenLifetime short (5-15 minutes) and use refresh tokensTokenContentLogging = false in production to avoid leaking sensitive data