ASP.NET Core Web API

Access Tokens & Refresh Tokens Workflow

2 Views Updated 5/4/2026

Role-Based & Policy-Based Authorization

Authentication answers "Who are you?". Authorization answers "Are you allowed to do this?". Once a user's token is authenticated, we must implement strict Authorization restrictions to ensure normal users cannot access Administrative endpoints.

1. Role-Based Authorization (The Simple Way)

If you included a ClaimTypes.Role in the JWT token (e.g., "Admin", "Manager", "User"), ASP.NET Core offers native attribute validation.

[ApiController]
[Route("api/admin")]
public class AdminController : ControllerBase
{
    // Authenticated, but MUST strictly possess the "Admin" role claim
    [Authorize(Roles = "Admin")]
    [HttpDelete("fire-employee/{id}")]
    public IActionResult FireEmployee(int id) 
    { ... }

    // Supports multiple roles (OR condition)
    [Authorize(Roles = "Admin,Manager")] 
    [HttpGet("view-reports")]
    public IActionResult ViewReports() 
    { ... }
}
Warning: Hardcoding strings like "Admin,Manager" everywhere creates brittle spaghetti code. When a company changes a job title from "Manager" to "Supervisor", you must hunt down and rewrite 50 attributes.

2. Policy-Based Authorization (The Enterprise Standard)

Instead of checking hardcoded roles, Policies allow you to define an abstract rule (e.g., "Require HR Clearance") in a central location. You then tag the controllers with the Policy. If the underlying logic changes, you only update it once.

Step 1: Define the Policy in Program.cs

builder.Services.AddAuthorization(options =>
{
    // Simple Policy matching roles
    options.AddPolicy("RequireHrClearance", policy => 
        policy.RequireRole("Admin", "HR_Manager"));

    // Complex Business Logic Policy evaluating specific claims
    options.AddPolicy("MustBeAge21", policy =>
        policy.RequireAssertion(context =>
        {
            var dobClaim = context.User.FindFirst("DateOfBirth");
            if (dobClaim == null) return false;
            
            var dob = DateTime.Parse(dobClaim.Value);
            return DateTime.Today.Year - dob.Year >= 21;
        }));
});

Step 2: Apply the Policy


[Authorize(Policy = "RequireHrClearance")]
[HttpPost("hire")]
public IActionResult HireEmployee() { ... }

[Authorize(Policy = "MustBeAge21")]
[HttpGet("restricted-data")]
public IActionResult GetRestrictedData() { ... }

3. Imperative Authorization

Sometimes Authorization logic cannot be decided via attributes because it depends on the precise data retrieved from the database. (e.g., "A user can only Edit an article if they are the original Author who wrote it.")

[HttpPut("{articleId}")]
[Authorize] // Just ensure they are logged in
public async Task<IActionResult> UpdateArticle(int articleId, ArticleDto dto)
{
    var article = await _db.Articles.FindAsync(articleId);
    if (article == null) return NotFound();

    // Imperative check: Find who is currently logged in
    var currentUserId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);

    // Verify ownership
    if (article.AuthorId != currentUserId)
    {
        return Forbid(); // HTTP 403: You are authenticated, but not authorized for THIS specific record
    }

    article.Content = dto.Content;
    await _db.SaveChangesAsync();
    return Ok();
}

4. Interview Mastery

Q: "What is the exact HTTP Status Code difference between returning Unauthorized() and Forbid()?"

Architect Answer: "It is a massive architectural distinction. `Unauthorized()` produces an HTTP 401. It means 'I do not know who you are. Your token is missing, invalid, or expired. You must authenticate yourself first.' `Forbid()` produces an HTTP 403. It means 'I know exactly who you are. Your token is perfectly valid and authenticated. However, your specific user account lacks the necessary permissions (roles/policies) to access this specific resource.' A 401 means 'Login again.' A 403 means 'Go away, you aren't high enough rank to see this.'"

ASP.NET Core Web API
1. Fundamentals & HTTP
Introduction to ASP.NET Core Web API REST Principles and HTTP Methods Controllers & ControllerBase Routing (Attribute vs Conventional) Action Return Types (IActionResult)
2. Request Handling
Model Binding (FromQuery, FromBody, FromRoute) Dependency Injection (DI) Deep Dive App Settings & The Options Pattern
3. Data Access & Architecture
EF Core Setup in Web API DbContext & Migrations Repository & Unit of Work Pattern Asynchronous Programming (async/await)
4. Data Transfer & Validation
Data Transfer Objects (DTOs) & AutoMapper Model Validation (DataAnnotations) FluentValidation Integration
5. Advanced Concepts
Global Exception Handling Middleware Content Negotiation (JSON vs XML) Pagination & Filtering Advanced Searching & Sorting HATEOAS (Hypermedia) Implementation Output Caching & Response Caching
6. Security & Authorization
Cross-Origin Resource Sharing (CORS) JWT Authentication Setup Access Tokens & Refresh Tokens Workflow Role-Based & Policy-Based Authorization API Key Authentication Rate Limiting & Throttling
7. Documentation & Testing
Swagger & OpenAPI Configuration Customizing API Documentation Unit Testing Controllers (xUnit & Moq) Integration Testing (WebApplicationFactory)
8. Microservices & Deployment
Consuming External APIs (IHttpClientFactory) Health Checks & Diagnostics API Versioning Strategies Deploying APIs (Docker & Azure)