Plinth.Security.Jwt
1.8.1
Prefix Reserved
dotnet add package Plinth.Security.Jwt --version 1.8.1
NuGet\Install-Package Plinth.Security.Jwt -Version 1.8.1
<PackageReference Include="Plinth.Security.Jwt" Version="1.8.1" />
<PackageVersion Include="Plinth.Security.Jwt" Version="1.8.1" />
<PackageReference Include="Plinth.Security.Jwt" />
paket add Plinth.Security.Jwt --version 1.8.1
#r "nuget: Plinth.Security.Jwt, 1.8.1"
#:package Plinth.Security.Jwt@1.8.1
#addin nuget:?package=Plinth.Security.Jwt&version=1.8.1
#tool nuget:?package=Plinth.Security.Jwt&version=1.8.1
README
Plinth.Security.Jwt
JWT 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.
- Supports Signed JWT (JWS) via
- HMAC with SHA-{256, 384, 512}
- RSA with SHA-{256, 384, 512}
- Supports Encrypted JWT (JWE) via
- AES-{128, 192, 256}-CBC-HMAC-{256, 384, 512}
- RSA-OAEP-{160, 256, 384, 512} with AES-{128, 192, 256}-CBC-HMAC-{256, 384, 512}
Setup
1. Install the Package
dotnet add package Plinth.Security.Jwt
2. Configure JWT Options
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();
3. Register with Dependency Injection
services.AddSingleton(jwtOptions);
services.AddSingleton<JwtValidator>();
services.AddSingleton<JwtGenerator>();
Usage
Creating JWTs
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 });
}
}
Adding Custom Claims
You can add custom claims to the JWT:
var jwtData = _jwtGenerator.GetBuilder(userId, userName, roles)
.AddClaim("department", "Engineering")
.AddClaim("employee_id", "12345")
.Build();
Validating JWTs
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" });
}
}
}
Refreshing Tokens
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" });
}
}
Security Modes
HMAC Signature (Symmetric)
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);
RSA Signature (Asymmetric)
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);
AES Encryption (Symmetric)
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);
RSA Encryption (Asymmetric)
Use for encrypted tokens in distributed systems:
var rsa = RSA.Create(2048);
// Or load from certificate store
var securityMode = new JwtSecurityModeRsaEncryption(rsa);
ClaimsPrincipal Extension Methods
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)
Best Practices
- Secure Key Storage: Store encryption/signing keys in secure configuration (Azure Key Vault, AWS Secrets Manager, etc.)
- Short Token Lifetimes: Keep
TokenLifetimeshort (5-15 minutes) and use refresh tokens - Disable Logging in Production: Set
TokenContentLogging = falsein production to avoid leaking sensitive data - HTTPS Only: Always transmit JWTs over HTTPS
- Validate on Every Request: Always validate tokens on protected endpoints
- Use Strong Keys: Use at least 256-bit keys for HMAC, 2048-bit for RSA
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Plinth.Common (>= 1.8.1)
- System.IdentityModel.Tokens.Jwt (>= 8.14.0)
-
net8.0
- Plinth.Common (>= 1.8.1)
- System.IdentityModel.Tokens.Jwt (>= 8.14.0)
- System.Text.Json (>= 10.0.0)
-
net9.0
- Plinth.Common (>= 1.8.1)
- System.IdentityModel.Tokens.Jwt (>= 8.14.0)
- System.Text.Json (>= 10.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Plinth.Security.Jwt:
| Package | Downloads |
|---|---|
|
Plinth.AspNetCore
Plinth ASP.NET Core Services Utilities |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.8.1 | 465 | 12/11/2025 |
| 1.8.0 | 382 | 11/13/2025 |
| 1.8.0-b211.72089fd9 | 242 | 11/12/2025 |
| 1.7.4 | 2,912 | 8/6/2025 |
| 1.7.3 | 234 | 8/2/2025 |
| 1.7.2 | 2,672 | 3/16/2025 |
| 1.7.1 | 1,204 | 12/12/2024 |
| 1.7.0 | 3,346 | 11/12/2024 |
| 1.6.6 | 1,066 | 11/8/2024 |
| 1.6.5 | 3,766 | 8/31/2024 |
| 1.6.4 | 743 | 8/2/2024 |
| 1.6.3 | 2,002 | 5/15/2024 |
| 1.6.2 | 743 | 2/16/2024 |
| 1.6.1 | 5,734 | 1/5/2024 |
| 1.6.0 | 2,286 | 11/30/2023 |
| 1.5.10-b186.aca976b4 | 147 | 11/30/2023 |
| 1.5.9 | 376 | 11/29/2023 |
| 1.5.9-b174.64153841 | 143 | 11/23/2023 |
| 1.5.9-b172.dfc6e7bd | 110 | 11/17/2023 |
| 1.5.9-b171.4e2b92e2 | 143 | 11/4/2023 |
| 1.5.8 | 931 | 10/23/2023 |
| 1.5.7 | 9,186 | 7/31/2023 |
| 1.5.6 | 4,676 | 7/13/2023 |
| 1.5.5 | 490 | 6/29/2023 |
| 1.5.4 | 1,482 | 3/7/2023 |
| 1.5.3 | 703 | 3/3/2023 |
| 1.5.2 | 906 | 1/11/2023 |
| 1.5.2-b92.7c961f5f | 248 | 1/11/2023 |
| 1.5.0 | 1,213 | 11/9/2022 |
| 1.5.0-b88.7a7c20cd | 236 | 11/9/2022 |
| 1.4.7 | 5,165 | 10/20/2022 |
| 1.4.6 | 1,843 | 10/17/2022 |
| 1.4.5 | 1,958 | 10/1/2022 |
| 1.4.4 | 1,985 | 8/16/2022 |
| 1.4.3 | 2,186 | 8/2/2022 |
| 1.4.2 | 1,982 | 7/19/2022 |
| 1.4.2-b80.7fdbfd04 | 265 | 7/19/2022 |
| 1.4.2-b74.acaf86f5 | 267 | 6/15/2022 |
| 1.4.1 | 2,107 | 6/13/2022 |
| 1.4.0 | 1,856 | 6/6/2022 |
| 1.3.8 | 3,055 | 4/12/2022 |
| 1.3.7 | 1,839 | 3/21/2022 |
| 1.3.6 | 1,842 | 3/17/2022 |
| 1.3.6-b67.ca5053f3 | 302 | 3/16/2022 |
| 1.3.6-b66.4a9683e6 | 263 | 3/16/2022 |
net10.0 support