Authentication in .NET

Authentication is the cornerstone of secure applications. Whether you're building APIs, Blazor apps, or microservices, understanding JWT tokens, Bearer authentication, and Identity Servers is essential.

In this 5-minute guide, we'll break down these concepts and show you how to implement them in .NET 10.

๐Ÿ” What is a JWT Token?

A JWT (JSON Web Token) is a compact, self-contained token that securely transmits information between parties as a JSON object. It's digitally signed, so you can trust its contents haven't been tampered with.

JWT Structure

A JWT consists of three parts separated by dots:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.signature
โ””โ”€โ”€โ”€โ”€ Header โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€ Payload โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€ Sig โ”€โ”˜
  • Header โ€” Algorithm & token type (alg, typ)
  • Payload โ€” Claims (user data, expiration, issuer)
  • Signature โ€” Verifies the token hasn't been tampered with

Common JWT Claims

  • iss (Issuer) โ€” Who created the token
  • sub (Subject) โ€” The user identifier
  • aud (Audience) โ€” Intended recipient
  • exp (Expiration) โ€” When the token expires
  • iat (Issued At) โ€” When the token was created

๐ŸŽซ What is a Bearer Token?

A Bearer Token is a type of access token included in HTTP requests using the Authorization header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

The term "bearer" means: "whoever bears (carries) this token is authorized."

๐Ÿ’ก Key insight: JWTs are commonly used as bearer tokens, but they're not the same thing. JWT is a format, while Bearer is a transport mechanism.

๐Ÿข What is an Identity Server?

An Identity Server (also called a Secure Token Service or STS) is a centralized authentication service that:

  • โœ… Authenticates users (login with credentials)
  • โœ… Issues tokens (JWT/access tokens)
  • โœ… Validates tokens for APIs
  • โœ… Supports standards like OAuth 2.0 and OpenID Connect (OIDC)
  • Duende IdentityServer โ€” .NET-based, self-hosted
  • Microsoft Entra ID โ€” Azure's cloud identity (formerly Azure AD)
  • Auth0 โ€” Cloud-based, easy integration
  • Keycloak โ€” Open-source, Java-based

๐Ÿ”„ How It Works: The Authentication Flow

Here's how the complete authentication flow works:

Authentication flow

Validation Steps

When the API receives a request, it validates:

  1. Signature โ€” Was this token created by a trusted issuer?
  2. Expiration โ€” Is the token still valid?
  3. Issuer (iss) โ€” Did the expected identity server issue this?
  4. Audience (aud) โ€” Is this token intended for this API?

๐Ÿ’ป Implementation in .NET 10

Let's implement JWT Bearer authentication in a .NET 10 application.

Step 1: Install the NuGet Package

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Step 2: Configure JWT Authentication

// Program.cs
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;

var builder = WebApplication.CreateBuilder(args);

// Add JWT Bearer authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "https://your-identity-server.com";
        options.Audience = "your-api-audience";
    });

builder.Services.AddAuthorization();

var app = builder.Build();

// Enable authentication & authorization middleware
app.UseAuthentication();
app.UseAuthorization();

// Public endpoint - no auth required
app.MapGet("/", () => "Hello, World!");

// Protected endpoint - requires valid JWT
app.MapGet("/secret", (ClaimsPrincipal user) => 
    $"Hello, {user.Identity?.Name}! This is secret data.")
    .RequireAuthorization();

app.Run();

Step 3: Protect Controllers (Alternative Approach)

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class WeatherController : ControllerBase
{
    [HttpGet]
    public IActionResult GetForecast()
    {
        return Ok(new { Temperature = 22, Unit = "Celsius" });
    }
    
    [AllowAnonymous]
    [HttpGet("public")]
    public IActionResult GetPublicData()
    {
        return Ok("This is public data");
    }
}

Step 4: Force Authentication Globally (Optional)

If you want all endpoints to require authentication by default:

var requireAuthPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();

builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(requireAuthPolicy);

๐Ÿ”‘ Understanding HTTP Response Codes

  • 200 OK โ€” Success: Valid token, authorized
  • 401 Unauthorized โ€” Authentication failed: Invalid/expired token, wrong signature
  • 403 Forbidden โ€” Authorization failed: Valid token, but insufficient permissions

โšก Quick Reference

  • JWT โ€” Self-contained token with encoded claims
  • Bearer Token โ€” Token sent in Authorization header
  • Identity Server โ€” Issues and validates tokens (OAuth/OIDC)
  • Access Token โ€” Short-lived token for API access
  • Refresh Token โ€” Long-lived token to get new access tokens

๐Ÿ›ก๏ธ Security Best Practices

  1. Always use HTTPS โ€” Never transmit tokens over unencrypted connections
  2. Validate all claims โ€” Issuer, audience, and expiration at minimum
  3. Use short expiration times โ€” Access tokens should expire in minutes, not days
  4. Store tokens securely โ€” Use HTTP-only cookies for web apps, secure storage for mobile
  5. Use asymmetric keys โ€” RSA or ECDSA signatures are more secure than symmetric keys

๐Ÿ“š Further Reading


See you next time for more on www.devskillsunlock.com ๐Ÿš€