Roadmap › ASP.NET Core Web API & REST › Module: Security
Lessons in this course (15)

9. JWT authentication

Intermediate★ Must knowLesson 9 of 15
csharp
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(o =>
    {
        o.Authority = "https://login.microsoftonline.com/<tenant-id>/v2.0";   // or your identity server
        o.Audience = "api://shop-api";
        // for self-issued tokens instead:
        // o.TokenValidationParameters = new() { ValidateIssuer = true, ValidIssuer = "...", ValidateAudience = true,
        //     ValidAudience = "...", ValidateLifetime = true, IssuerSigningKey = new SymmetricSecurityKey(keyBytes), ClockSkew = TimeSpan.FromMinutes(1) };
    });
builder.Services.AddAuthorization(o => o.AddPolicy("orders.write", p => p.RequireClaim("scp", "Orders.Write")));

app.UseAuthentication();
app.UseAuthorization();

A JWT has three Base64Url parts: header.payload.signature. The payload holds claims (sub, iss, aud, exp, iat, roles/scopes). It is signed, not encrypted — anyone can read it, so never put secrets in it. The server validates signature, issuer, audience and expiry without a DB lookup (stateless).

  • Access token: short-lived (5–60 min). Refresh token: long-lived, stored securely, rotated on use, revocable server-side.
  • OAuth 2.0 flows: Authorization Code + PKCE (SPAs, mobile, web), Client Credentials (service-to-service). Implicit and password grants are deprecated.
  • OpenID Connect adds identity (ID token) on top of OAuth 2.0.