Learn .NET - Security & Identity
Series/Learn .NET/Episode 12
Episode 12 of 23

Learn .NET - Security & Identity

This episode teaches security in ASP.NET Core: authentication and authorization, JWT bearer tokens, policy-based authorization, OAuth2 and OpenID Connect integration, and secure headers, CORS, and data protection to secure web applications.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

An open web API is an invitation to be misused. Episode 12 teaches the security layer in ASP.NET Core: authentication to verify who the user is, and authorization to determine what they are allowed to do. Both are the foundation of every production application.

You will learn JWT bearer tokens, policy-based authorization, integration with OAuth2 and OpenID Connect, and protective practices such as secure headers, CORS, and data protection. This is the most important episode for building a trusted system.

Authentication and Authorization

Two Different Concepts

Authentication answers who are you, authorization answers what are you allowed to do. In ASP.NET Core these are separate middlewares that run in sequence. Authentication establishes the user's identity; authorization checks their claims.

Enable authentication and authorization
app.UseAuthentication();
app.UseAuthorization();
 
app.MapGet("/api/admin", () => "rahasia")
    .RequireAuthorization("AdminOnly");

app.UseAuthentication() and app.UseAuthorization() are installed as middleware. .RequireAuthorization("AdminOnly") restricts the endpoint based on a policy — requests without a valid token are rejected with 401.

JWT Bearer Tokens

Configuring JWT Bearer

A JWT is an encrypted token that carries user claims. Enable it with the JwtBearer package:

Install JwtBearer
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Then register the bearer scheme in Program.cs:

JWT bearer configuration
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = builder.Configuration["Auth:Authority"];
        options.Audience = builder.Configuration["Auth:Audience"];
        options.TokenValidationParameters.ValidateIssuer = true;
    });

AddJwtBearer validates JWT tokens on arrival. Authority points to the token provider (for example, IdentityServer or Azure AD), and Audience ensures the token is indeed intended for this API. The public keys are carried by the provider, so the API does not need to store secrets. Protected endpoints simply need the Authorization: Bearer <token> header on the client side.

Issuing Tokens

Tokens are issued by an identity provider, not by an ordinary API. The basic flow:

  1. The client logs in to the identity provider.
  2. The provider issues a JWT containing claims.
  3. The client sends the JWT in the Authorization: Bearer <token> header.
  4. The API validates it and reads the user's claims.

The API only checks the token's validity and never leaks its signing secret.

Policy-Based Authorization

Policies from Claims

Policies enable dynamic authorization rules based on claims:

Register a policy
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy =>
        policy.RequireClaim("role", "admin"));
});

AddPolicy("AdminOnly", ...) defines the rule: the user must have a role claim with the value admin. Endpoints using RequireAuthorization("AdminOnly") can only be accessed by users with that claim.

Custom Requirements

For complex authorization logic, create a custom requirement:

Custom requirement
public class UsiaMinimalRequirement : IAuthorizationRequirement
{
    public int UmurMinimal { get; set; }
}

Requirements are implemented in a handler that evaluates the user context. This gives full flexibility — for example, checking resource ownership, not just roles.

OAuth2 and OpenID Connect

Industry Standards

OAuth2 governs the granting of access (authorization), while OpenID Connect adds an identity layer on top of it. ASP.NET Core supports both natively:

OpenID Connect integration
builder.Services.AddOpenIdConnect("oidc", options =>
{
    options.Authority = builder.Configuration["Oidc:Authority"];
    options.ClientId = builder.Configuration["Oidc:ClientId"];
    options.ClientSecret = builder.Configuration["Oidc:ClientSecret"];
    options.ResponseType = "code";
});

AddOpenIdConnect lets the application use an external provider — Azure AD, Auth0, Keycloak, or IdentityServer. This approach saves you from writing your own login logic, password hashing, and session handling.

Secure Headers, CORS, and Data Protection

Security Headers and CORS

HTTP responses must carry security headers. Enable HTTPS redirect and configure CORS explicitly:

HTTPS and CORS
app.UseHsts();
app.UseHttpsRedirection();
 
app.UseCors(policy => policy
    .WithOrigins("https://app.example.com")
    .AllowAnyHeader()
    .AllowAnyMethod());

UseHsts forces browsers to use HTTPS, and UseHttpsRedirection redirects HTTP requests. CORS with .WithOrigins restricts the origins allowed to access the API — do not use AllowAnyOrigin in production unless truly necessary.

Data Protection API

The Data Protection API encrypts sensitive data such as cookies and temporary tokens:

Encrypt with Data Protection
var protector = dataProtector.CreateProtector("Sensitive.v1");
 
string terenkripsi = protector.Protect("data rahasia");
string plain = protector.Unprotect(terenkripsi);

CreateProtector creates a protector with a named purpose, and Protect/Unprotect encrypt and decrypt data. The protection keys are managed automatically by the runtime and should be persisted so tokens stay valid when the application restarts.

Warning

Never store plaintext passwords. Use ASP.NET Core Identity or an established hashing library, and never put secrets in configuration that gets committed to Git.

Security Practice Summary

  • Install UseAuthentication before UseAuthorization.
  • Use JWT bearer with correct Authority and Audience.
  • Define policies from claims; custom requirements for complex logic.
  • Integrate OpenID Connect for external identity providers.
  • Apply HSTS, HTTPS redirect, and strict CORS.
  • Encrypt sensitive data with the Data Protection API.

Closing

Key takeaways:

  • Authentication verifies identity; authorization manages access rights.
  • JWT bearer validates tokens via Authority and Audience.
  • Policy-based authorization reads claims to restrict endpoints.
  • OAuth2 and OpenID Connect delegate identity to external providers.
  • Secure headers, CORS, and HTTPS are the basics of transport protection.
  • The Data Protection API protects sensitive data in applications.

In the next episode 13 we will discuss secure coding practices — input validation and output encoding, preventing injection, XSS, CSRF, and sensitive data leaks, secure storage with the Data Protection API, and production security best practices.

Learn .NET - Security & Identity | Learn .NET