Creating JWT Tokens with Microsoft.IdentityModel.JsonWebTokens
Problem Statement
When migrating from System.IdentityModel.Tokens.Jwt
to the newer Microsoft.IdentityModel.JsonWebTokens
library, developers often struggle to convert existing token generation code. The original approach (JwtSecurityTokenHandler
) uses a different pattern than the newer JsonWebTokenHandler
, leading to confusion about:
- Proper token descriptor configuration
- Claims representation
- Timestamp handling
- Signing credential setup
Solution: Using JsonWebTokenHandler
Step-by-Step Implementation
Here's the modern approach using Microsoft.IdentityModel.JsonWebTokens
:
using System.Text;
using Microsoft.IdentityModel.Tokens;
// 1. Prepare security key
byte[] keyData = Encoding.UTF8.GetBytes("SomeStringFromConfig1234");
var securityKey = new SymmetricSecurityKey(keyData);
// 2. Configure claims (as dictionary)
var claims = new Dictionary<string, object>
{
[ClaimTypes.Name] = "Testuser",
[ClaimTypes.GroupSid] = "Tenant1",
[ClaimTypes.Sid] = "3c545f1c-cc1b-4cd5-985b-8666886f985b"
};
// 3. Set up token descriptor
var descriptor = new SecurityTokenDescriptor
{
Issuer = "MyIssuer",
Audience = "MyAudience",
Claims = claims,
IssuedAt = null, // Explicitly disable auto-generation
NotBefore = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddMinutes(120),
SigningCredentials = new SigningCredentials(
securityKey,
SecurityAlgorithms.HmacSha256Signature
)
};
// 4. Create handler and generate token
var handler = new JsonWebTokenHandler();
handler.SetDefaultTimesOnTokenCreation = false; // Critical for manual timestamp control
string tokenString = handler.CreateToken(descriptor);
Key Differences Explained
Claims Representation
Claims are now aDictionary<string, object>
instead ofList<Claim>
. This directly maps to JWT claims without conversion overhead.Timestamp Control
By settingSetDefaultTimesOnTokenCreation = false
, we:- Disable automatic
iat
(IssuedAt) generation - Gain explicit control over
nbf
(NotBefore) andexp
(Expiry) - Avoid duplicate timestamp claims
- Disable automatic
Token Creation Workflow
Uses a handler/descriptor pattern instead of constructing token objects:JsonWebTokenHandler + SecurityTokenDescriptor → CreateToken()
Output Validation
Both approaches generate identical JWT payloads:
{
"aud": "MyAudience",
"iss": "MyIssuer",
"exp": 1709078400,
"nbf": 1708992000,
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "Testuser",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid": "Tenant1",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid": "3c545f1c-cc1b-4cd5-985b-8666886f985b"
}
Important Considerations
- Key Length: HMAC-SHA256 requires keys ≥256 bits (32+ characters)
- Clock Skew: Production systems should handle minor time mismatches
- Token Validation: Pair with
TokenValidationParameters
for validation
Performance Benefit
Microsoft benchmarks show ~30% faster token processing with JsonWebTokenHandler
versus the legacy library
Common Errors
- Automatic timestamps: Forgetting
handler.SetDefaultTimesOnTokenCreation = false
addsiat
- Byte padding: Incorrect key encoding causes security exceptions
- Claim collisions: Duplicate keys in dictionary result in overwrites
Best Practices
- Store sensitive keys in secure configuration (Azure Key Vault, environment variables)
- Validate tokens using the same library version
- Prefer
RsaSecurityKey
over symmetric keys where possible
var validationParams = new TokenValidationParameters
{
ValidIssuer = "MyIssuer",
ValidAudience = "MyAudience",
IssuerSigningKey = securityKey
};
TokenValidationResult result = handler.ValidateToken(tokenString, validationParams);