Learn C# - Security & Identity
Series/Learn C#/Episode 12
Episode 12 of 23

Learn C# - Security & Identity

This episode secures ASP.NET Core applications: ASP.NET Core Identity for user management, the authentication pipeline, JWT authentication and authorization policies, OAuth2 and OpenID Connect integration, and secure headers, CORS, and token management.

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

Introduction

An open API without security is an invitation to be attacked. Every real application must know who its users are (authentication), what those users are allowed to do (authorization), and how to keep their identities safe.

ASP.NET Core provides a complete security foundation: Identity for user management, a pluggable authentication middleware, and support for JWT and OAuth2/OpenID Connect.

Episode 12 builds the security layer step by step: Identity, JWT, authorization policies, OAuth2 integration, and secure headers and CORS.

ASP.NET Core Identity and the Authentication Pipeline

Setting Up Identity

ASP.NET Core Identity handles users, password hashing, roles, and claims, with storage in EF Core. Add the package and register its services:

Adding the Identity package
dotnet add src/Toko.Api package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Identity registration
var builder = WebApplication.CreateBuilder(args);
 
builder.Services.AddDbContext<TokoContext>(o =>
    o.UseSqlite("Data Source=toko.db"));
 
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
    .AddEntityFrameworkStores<TokoContext>();
 
var app = builder.Build();
app.MapIdentityApi<IdentityUser>();
app.Run();

AddIdentityApiEndpoints provides standard endpoints such as register and login. The authentication pipeline works as middleware: each request gets an identity from a token or cookie, then the authorization policy decides whether the request is forwarded.

JWT Authentication and Authorization Policies

Adding JWT Authentication

For APIs consumed by mobile applications or SPAs, JWT is the primary choice. A JWT is a signed string containing the user's claims:

Adding the JWT Bearer package
dotnet add src/Toko.Api package Microsoft.AspNetCore.Authentication.JwtBearer
JWT Bearer configuration
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "https://id.contoh.id";
        options.Audience = "toko-api";
    });
 
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy =>
        policy.RequireRole("Admin"));
});

AddJwtBearer validates the token signature and claims on every request. The AdminOnly policy ensures only users with the Admin role can access certain endpoints.

Applying Policies in Controllers

Apply policies with an attribute on the controller or action:

Protecting an endpoint
[ApiController]
[Route("api/admin")]
public class AdminController : ControllerBase
{
    [HttpGet]
    [Authorize(Policy = "AdminOnly")]
    public IActionResult Get() => Ok("Hanya admin yang bisa melihat ini.");
 
    [HttpDelete]
    [Authorize]
    public IActionResult Hapus() => Ok("Semua pengguna yang login boleh menghapus.");
}

The [Authorize] attribute without arguments just requires a logged-in user, while [Authorize(Policy = "AdminOnly")] requires a specific role.

OAuth2 and OpenID Connect

External Provider Integration

For single sign-on with an external provider, register an OpenID Connect or OAuth handler:

Logging in with an external provider
builder.Services.AddAuthentication()
    .AddOpenIdConnect("google", options =>
    {
        options.ClientId = "client-id-anda";
        options.ClientSecret = "client-secret-anda";
        options.Authority = "https://accounts.google.com";
        options.ResponseType = "code";
        options.Scope.Add("email");
    });

With the configuration above, the login flow follows the OAuth2/OpenID Connect protocol: the application redirects the user to the provider, receives a code, then exchanges it for tokens. This pattern avoids managing passwords yourself — for both security and user experience.

Secure Headers, CORS, and Token Management

Secure Headers and CORS

Browsers enforce security policies through HTTP headers. ASP.NET Core can add security headers automatically:

Secure headers and CORS
app.UseHsts();
app.UseHttpsRedirection();
 
app.UseCors(policy => policy
    .WithOrigins("https://app.contoh.id")
    .AllowAnyHeader()
    .AllowAnyMethod());

UseHsts tells the browser to always use HTTPS. The CORS configuration above only allows the origin https://app.contoh.id — never use AllowAnyOrigin without careful thought, because it opens your API to any website.

Token Management

JWTs should be short-lived and paired with refresh tokens. Limit the validity period with TokenValidationParameters and always send tokens in the Authorization header, not in the URL:

Calling an API with a token
curl -H "Authorization: Bearer <token>" https://api.contoh.id/api/admin

The curl -H "Authorization: Bearer <token>" command above sends the token through a safe header. Never put tokens in a query string — they'll be recorded in server logs and browser history.

Closing

Key takeaways:

  • Identity handles users and roles with EF Core storage.
  • JWT Bearer validates tokens on every request.
  • Authorization policies like RequireRole separate access rights per endpoint.
  • OAuth2/OpenID Connect moves password management to an external provider.
  • Security headers, strict CORS, and short-lived tokens keep things secure.

In the next episode 13 we deepen the security side of code: secure coding and best practices — input validation and sanitization, the OWASP Top 10 for .NET, the Data Protection API, and preventing injection, XSS, CSRF, and sensitive data leakage.

Learn C# - Security & Identity | Learn C#