Because REST APIs are inherently Stateless, they cannot use Session Cookies to remember who logged in. JSON Web Tokens (JWT) solve this. The server cryptography signs a token verifying the user's identity, hands it to the client, and the client simply attaches it to the HTTP Headers of all subsequent requests.
If you inspect an encoded JWT (e.g., eyJhb...), it consists of three Base64 encoded sections separated by periods.
appsettings.json. If a hacker alters the UserID in the Payload from 2 to 1 to steal an admin account, the Signature breaks instantly.We must define our Secret Key, Issuer (Who created the token), and Audience (Who the token is meant for) securely.
{
"Jwt": {
"Key": "SuperSecretKeyThatMustBeAtLeast256BitsLongForSha256!",
"Issuer": "https://api.mycompany.com",
"Audience": "https://react.mycompany.com"
}
}
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
In Program.cs, we must explicitly tell the ASP.NET Core Authentication pipeline how to validate incoming tokens.
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// 1. Configure the Authentication Scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
// 2. Define exactly how a token is verified as "Valid"
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true, // Ensure token hasn't expired
ValidateIssuerSigningKey = true, // Ensure hacker didn't fake the signature
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
var app = builder.Build();
// 3. ACTIVATING THE PIPELINE (Order is absolute!)
app.UseAuthentication(); // First, figure out WHO the user is
app.UseAuthorization(); // Second, determine IF they are allowed to access the endpoint
Q: "If a user is fired from the company immediately, but their JWT token doesn't expire for another 6 hours, how do we revoke their token instantly since JWTs are stateless and the server isn't tracking them?"
Architect Answer: "This is the primary weakness of pure stateless JWTs; they cannot be instantly revoked. By default, the server will trust the cryptographic signature for the next 6 hours. Enterprise applications solve this using a hybrid approach: JWTs are given extremely short lifespans (e.g., 15 minutes) combined with long-lived 'Refresh Tokens' stored in a physical database. When the 15-minute JWT expires, the client sends the Refresh Token to the server to get a new one. The server checks the DB, realizes the user was fired, deletes the refresh token, and denies the new JWT. Alternatively, for instant revocation, you must implement a globally distributed Redis 'Deny-list' where revoked JWT Signatures are cached until they expire, checking every incoming JWT against it."