Why JWT for APIs
JSON Web Tokens are self-contained, signed tokens that let a Web API validate a caller's identity without querying a session store on every request, which is why they're the default choice for stateless REST and SPA-facing APIs where cookie-based Identity sessions don't fit well. A JWT consists of a Base64Url-encoded header, payload (claims like sub, exp, and custom claims), and signature, separated by dots, and the signature — created with either a symmetric key (HMAC-SHA256) or an asymmetric key pair (RS256) — lets the API verify the token wasn't tampered with since issuance.
Cricket analogy: A JWT is like a DRS (Decision Review System) ball-tracking readout — once generated and signed off by the technology, any umpire on the ground can trust it instantly without re-running the entire review process from scratch.
Issuing Tokens
On the issuing side — typically an /api/auth/login endpoint — you verify the user's credentials, then build a JWT using System.IdentityModel.Tokens.Jwt's JwtSecurityTokenHandler or the newer Microsoft.IdentityModel.JsonWebTokens JsonWebTokenHandler. You populate a ClaimsIdentity with claims such as ClaimTypes.NameIdentifier and any custom claims like role or tenant_id, set an expiration (exp) that's typically short (15-60 minutes), sign it with a SigningCredentials built from a symmetric SecurityKey and an algorithm like SecurityAlgorithms.HmacSha256, and return the serialized token string to the client.
Cricket analogy: Issuing a JWT is like the third umpire's booth printing an official review certificate for a specific delivery — it bundles specific facts (claims) about that one ball, timestamps it, and signs off before handing it out.
Validating Tokens in the API
On the API side, you register the JWT bearer scheme with AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => ...), configuring TokenValidationParameters with ValidateIssuer, ValidateAudience, ValidateLifetime, and ValidateIssuerSigningKey all set to true, plus the expected issuer, audience, and signing key. Every incoming request with an Authorization: Bearer <token> header is validated by middleware before your controller runs; if validation fails (expired, wrong signature, wrong audience) the pipeline short-circuits with a 401 automatically, and [Authorize] attributes on controllers or actions enforce that a valid token is required at all.
Cricket analogy: TokenValidationParameters checking issuer and expiry is like the on-field umpire checking that a DRS certificate came from the actual official review center and hasn't expired past the over — reject anything that fails either check immediately.
// Program.cs - configure JWT bearer authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
// AuthController.cs - issue a token after verifying credentials
[HttpPost("login")]
public IActionResult Login(LoginRequest req)
{
if (!_userService.ValidateCredentials(req.Email, req.Password))
return Unauthorized();
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, req.Email),
new Claim(ClaimTypes.Role, "Member")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddMinutes(30),
signingCredentials: creds);
return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
}JWTs cannot be revoked once issued — the server has no built-in way to invalidate a still-valid, unexpired token. Keep access token lifetimes short (minutes, not days) and pair them with a separate refresh-token flow so a compromised token has a limited window of usefulness.
Never put sensitive data like passwords or full credit card numbers inside a JWT payload — the payload is only Base64Url-encoded, not encrypted, so anyone holding the token can decode and read its claims even without the signing key.
- JWTs are self-contained, signed tokens that let APIs validate identity without a server-side session lookup on every call.
- A token has three parts — header, payload (claims), and signature — joined by dots and Base64Url-encoded.
- Tokens are issued after credential verification, typically with a short expiration and signed via HMAC-SHA256 or RS256.
- AddJwtBearer with TokenValidationParameters enforces issuer, audience, lifetime, and signature checks automatically.
- JWT payloads are readable by anyone, not encrypted, so sensitive data should never be placed inside claims.
- Since JWTs can't be revoked before expiry, keep access tokens short-lived and use refresh tokens for longer sessions.
- [Authorize] on controllers/actions enforces that a valid bearer token is present before the action executes.
Practice what you learned
1. What are the three dot-separated parts of a JWT?
2. Why should sensitive data never be placed in a JWT's payload claims?
3. Which TokenValidationParameters setting ensures the API rejects a token that has expired?
4. Why can't a JWT be revoked before its expiration by default?
5. What is the practical mitigation for JWTs not being revocable before they expire?
Was this page helpful?
You May Also Like
Authentication with ASP.NET Core Identity
Learn how ASP.NET Core Identity manages users, passwords, and cookie-based sign-in for server-rendered and hybrid applications.
Authorization Policies and Roles
Learn how ASP.NET Core moves beyond simple role checks into flexible, claims-based authorization policies for fine-grained access control.
Securing APIs: Best Practices
A practical checklist of defense-in-depth techniques for hardening ASP.NET Core Web APIs beyond basic authentication and authorization.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics