Are you really sure you understand how JWT works under the hood in .NET? Most developers think they do – until a subtle bug hits production!
In this complete guide, I’ll walk you through real, practical examples of generating and validating JWT tokens in C# using .NET. By the end, you’ll not only know how it works but feel confident implementing secure authentication in your applications.
Introduction to JWT: Why Should You Care?
JSON Web Tokens (JWT) are a compact, URL-safe way to represent claims securely between two parties. In modern .NET apps, JWTs are the standard for authentication in microservices, APIs, and SPAs (Single Page Applications).

You should care because:
- JWTs are stateless (no need for server session storage).
- They’re widely adopted (ASP.NET Core, Angular, React, mobile apps).
- They can securely transmit user identity and roles.
- JWTs enable scalable architectures without centralized session databases.
- Built-in standard fields like
exp
,iss
,aud
help automate validation easily.
In short: Mastering JWT = creating scalable, secure authentication.
How to Generate a JWT Token in C#

Let’s start by building a JWT manually. Here’s a minimal working example in .NET:
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MySuperSecretKey12345"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "user@example.com"),
new Claim("role", "Admin"),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var token = new JwtSecurityToken(
issuer: "yourapp.com",
audience: "yourapp.com",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: credentials
);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
Console.WriteLine(jwt);
Explanation:
SymmetricSecurityKey
creates a shared secret key.SigningCredentials
defines the algorithm (HMAC SHA256).JwtRegisteredClaimNames.Jti
provides a unique ID to prevent replay attacks.- Token is issued for “yourapp.com” users and expires after 30 minutes.
Tip: Always rotate signing keys periodically.
How to Validate a JWT Token in C#

Validation is crucial to prevent token forgery or misuse. Here’s a full example:
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes("MySuperSecretKey12345");
try
{
tokenHandler.ValidateToken(tokenString, new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "yourapp.com",
ValidAudience = "yourapp.com",
IssuerSigningKey = new SymmetricSecurityKey(key),
ClockSkew = TimeSpan.Zero // No leeway on expiration
}, out SecurityToken validatedToken);
Console.WriteLine("Token is valid!");
}
catch (SecurityTokenExpiredException)
{
Console.WriteLine("Token has expired.");
}
catch (Exception ex)
{
Console.WriteLine($"Token validation failed: {ex.Message}");
}
Explanation:
- Verifies token’s signature using secret key.
- Confirms token’s issuer (
iss
) and audience (aud
). - Checks expiration (
exp
) precisely usingClockSkew = TimeSpan.Zero
. - Different exceptions help diagnose specific token issues.
Tip: Log validation errors to monitor attacks or misconfigurations.
Adding Custom Claims to JWT Tokens
Claims let you embed custom metadata into tokens. Let’s add more interesting claims:
var claims = new[]
{
new Claim("userId", Guid.NewGuid().ToString()),
new Claim("permission", "Admin:Write,Admin:Delete"),
new Claim("tenantId", "Company123"),
new Claim("loginTime", DateTime.UtcNow.ToString("o"))
};
Explanation:
userId
: Unique user identifier.permission
: Comma-separated string of access rights.tenantId
: Helps in multi-tenant applications.loginTime
: ISO8601 login timestamp.
Tip: Validate critical custom claims during API authorization.
Refresh Tokens: Handling Expiration Gracefully
JWTs must expire — but users hate being logged out mid-session. Here’s how you fix that:
Example pseudo-code:
// Generate Refresh Token
string GenerateRefreshToken()
{
return Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
}
// Validate and Renew
if (jwtTokenExpired && validRefreshToken)
{
// Issue new JWT + new Refresh Token
var newJwt = GenerateJwt();
var newRefresh = GenerateRefreshToken();
SaveRefreshToken(newRefresh);
}
Explanation:
GenerateRefreshToken
creates cryptographically strong tokens.- New JWTs are issued automatically without forcing user re-login.
- Server securely stores refresh tokens (e.g., database).
Tip: Bind refresh tokens to device fingerprint or IP for extra security.
FAQ: Common Questions About JWT in .NET
Yes! JWTs are base64-encoded, not encrypted. Never store secrets inside claims.
Use HttpOnly Secure Cookies for better security against XSS attacks.
They can impersonate the user. Short expiration + refresh token strategy helps minimize risk.
Yes, for APIs that need stronger security or cross-service validation.
Conclusion: Secure Your .NET Applications With Confidence
If you’ve made it this far, you’re not just another developer — you’re someone serious about doing authentication right. Mastering JWT in C# is your first step toward building apps that users trust and attackers fear.
Don’t just store this knowledge away; take action today! Review your existing projects, identify weak points, and integrate JWT best practices immediately. The best time to secure your applications was yesterday. The second-best time is right now.
What part of your application will you fortify first? Share your thoughts or challenges below — let’s secure the future together!