.NET Authentication & Authorization (Web API)

Created
Sep 5, 2025 05:59 PM
Tags
This note is structured to prepare you for interviews and practical usage of Authentication (AuthN) and Authorization (AuthZ) in .NET Web APIs.
We’ll start with fundamentals, cover the Microsoft recommended approach, and then move into advanced topics.

1. Fundamentals

Authentication vs Authorization

  • Authentication (AuthN) → Proving who you are.
  • Authorization (AuthZ) → Determining what you can do.
In Web APIs:
  • AuthN is usually handled via tokens (JWT, cookies, OAuth).
  • AuthZ is enforced via roles, claims, and policies.

2. Common Patterns in .NET Web API

🔹 ASP.NET Core Identity (with EF Core)

  • Provides user & role management, login/registration.
  • Usually paired with MVC/Razor apps.
  • Can generate JWT tokens for APIs.
  • Heavyweight if you just need token validation.

🔹 JWT Bearer Authentication (Standard for APIs)

  • Stateless, scalable.
  • Clients send a Bearer token in the Authorization header.
  • Recommended by Microsoft for Web APIs.
GET /weatherforecast HTTP/1.1 Host: api.example.com Authorization: Bearer eyJhbGciOi...

3. Implementing JWT Authentication

3.1 Configure Authentication in Program.cs

builder.Services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "<https://demo.identityserver.io>"; // Identity Provider options.Audience = "myapi"; // API identifier }); builder.Services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin")); }); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); app.MapGet("/secure", [Authorize] () => "Secure endpoint"); app.MapGet("/admin", [Authorize(Roles = "Admin")] () => "Admin endpoint"); app.Run();

3.2 Generating JWTs (Custom Auth Server)

If you manage your own users:
var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, user.Id), new Claim(ClaimTypes.Role, "Admin"), }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: config["Jwt:Issuer"], audience: config["Jwt:Audience"], claims: claims, expires: DateTime.Now.AddHours(1), signingCredentials: creds ); return new JwtSecurityTokenHandler().WriteToken(token);

4. Authorization in Depth

4.1 Role-Based Authorization

[Authorize(Roles = "Admin")] [HttpGet("/admin-data")] public IActionResult GetAdminData() => Ok("Only Admins can access this");

4.2 Claims-Based Authorization

[Authorize(Policy = "CanDelete")] [HttpDelete("/delete-resource")] public IActionResult DeleteResource() => Ok("Resource deleted");
Registering policy in Program.cs:
builder.Services.AddAuthorization(options => { options.AddPolicy("CanDelete", policy => policy.RequireClaim("permission", "delete")); });

4.3 Custom Policy Handlers

public class MinimumAgeRequirement : IAuthorizationRequirement { public int Age { get; } public MinimumAgeRequirement(int age) => Age = age; } public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement> { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, MinimumAgeRequirement requirement) { var dobClaim = context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth); if (dobClaim != null && DateTime.TryParse(dobClaim.Value, out var dob)) { if (DateTime.Today.Year - dob.Year >= requirement.Age) context.Succeed(requirement); } return Task.CompletedTask; } } // Register in Program.cs builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>(); builder.Services.AddAuthorization(options => { options.AddPolicy("Over18", policy => policy.Requirements.Add(new MinimumAgeRequirement(18))); });
Usage:
[Authorize(Policy = "Over18")] [HttpGet("/restricted")] public IActionResult GetRestricted() => Ok("Only 18+ can access");

5. Advanced Topics

5.1 Combining Multiple Schemes

  • Support JWT + API Key + Cookies in the same app.
builder.Services.AddAuthentication() .AddJwtBearer("Jwt", ...) .AddScheme<ApiKeyOptions, ApiKeyHandler>("ApiKey", ...);

5.2 Resource-Based Authorization

  • Instead of just roles/claims, authorization depends on the resource instance.
public class DocumentAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Document> { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, Document resource) { if (requirement.Name == "Edit" && resource.OwnerId == context.User.Identity.Name) context.Succeed(requirement); return Task.CompletedTask; } }

5.3 External Providers (Azure AD / Entra ID)

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(options => { configuration.Bind("AzureAd", options); }, options => { configuration.Bind("AzureAd", options); });
  • Delegates authentication to Azure AD.
  • Common for enterprise-grade apps.

5.4 Policy vs Role vs Claims

Approach
When to Use
Roles
Coarse-grained access (Admin, Manager)
Claims
Finer control (delete, export, department=HR)
Policies
Custom logic, often combining multiple claims/roles

6. Quick Comparison: Identity vs JWT

Feature
ASP.NET Core Identity
JWT Bearer Auth (Standard)
User Store
Built-in with EF Core
External (Azure AD, IdentityServer) or custom
Best for
Full app (UI + API)
Stateless APIs
State
Database-backed
Token-based, stateless
Complexity
Higher (DB migrations, tables)
Lower (validate token)

7. Interview-Ready Summary

  1. AuthN vs AuthZ – Know the difference.
  1. Web APIs should be stateless → JWT is standard.
  1. ASP.NET Core Identity → only when managing users inside your app.
  1. Roles, Claims, Policies → 3 levels of authorization.
  1. Advanced → Custom policy handlers, resource-based auth, external identity providers.

✅ With this, you can answer both theoretical and coding interview questions on .NET Authentication & Authorization.