Role-Based Access Control (RBAC) & Claims-Based Authorization in ASP.NET Core (In Depth)

Samim.Hossain
Samim Hossain
Published on Mar, 22 2026 2 min read 0 comments
image

Authentication answers who you are.
Authorization answers what you are allowed to do.

In real-world ASP.NET Core applications, authorization is built using Roles, Claims, and Policies. In this article, we’ll explore RBAC and Claims-Based Authorization deeply and show how to design scalable, secure access control systems.

Authorization Models Explained

| Model        | Description                    | Example                |
| ------------ | ------------------------------ | ---------------------- |
| RBAC         | Access based on role           | Admin, Editor, User    |
| Claims-Based | Access based on attributes     | Department, Permission |
| Policy-Based | Rules combining roles & claims | Admin OR Manager       |

ASP.NET Core supports all three, and they can be combined.

Role-Based Access Control (RBAC)

What Is RBAC?

RBAC assigns roles to users, and permissions are granted based on those roles.

Example Roles

  • Admin
  • Manager
  • Editor
  • User

Using Roles in ASP.NET Core Identity

Assigning a Role

await _userManager.AddToRoleAsync(user, "Admin");

Protecting an Endpoint with Role

[Authorize(Roles = "Admin")]
[HttpGet("admin/dashboard")]
public IActionResult AdminDashboard()
{
    return Ok("Admin only data");
}

Multiple Roles

[Authorize(Roles = "Admin,Manager")]

Role-Based Authorization (Pros & Cons)

✅ Pros

  • Simple to implement
  • Easy to understand

❌ Cons

  • Not flexible
  • Role explosion problem
  • Hard to scale in large systems

👉 That’s why claims-based authorization exists.

Claims-Based Authorization

What Are Claims?

A claim is a key–value pair describing a user.

{
  "sub": "123",
  "email": "[email protected]",
  "department": "finance",
  "permission": "can_view_reports"
}

Common Claim Types

  • Email
  • UserId
  • Department
  • Permissions
  • Subscription level

Adding Claims to JWT Token

var claims = new List<Claim>
{
    new Claim(ClaimTypes.NameIdentifier, user.Id),
    new Claim("department", "finance"),
    new Claim("permission", "view_reports")
};

Accessing Claims in Controller

var department = User.FindFirst("department")?.Value;

Policy-Based Authorization (Recommended)

Policies allow you to define complex authorization rules.

Defining Authorization Policies

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("FinanceOnly", policy =>
        policy.RequireClaim("department", "finance"));

    options.AddPolicy("ReportAccess", policy =>
        policy.RequireClaim("permission", "view_reports"));
});

Using Policies in Controllers

[Authorize(Policy = "FinanceOnly")]
[HttpGet("finance/reports")]
public IActionResult GetFinanceReports()
{
    return Ok("Finance data");
}

Combining Roles & Claims

options.AddPolicy("AdminOrManager", policy =>
{
    policy.RequireRole("Admin", "Manager");
});

 

options.AddPolicy("AdminWithPermission", policy =>
{
    policy.RequireRole("Admin");
    policy.RequireClaim("permission", "delete_user");
});

Custom Authorization Requirement

For advanced logic, create custom requirements.

Create Requirement

public class MinimumAgeRequirement : IAuthorizationRequirement
{
    public int Age { get; }
    public MinimumAgeRequirement(int age) => Age = age;
}

Create Handler

public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        MinimumAgeRequirement requirement)
    {
        var ageClaim = context.User.FindFirst("age");
        if (ageClaim != null && int.Parse(ageClaim.Value) >= requirement.Age)
            context.Succeed(requirement);

        return Task.CompletedTask;
    }
}

Register Custom Policy

options.AddPolicy("Age18Plus", policy =>
    policy.Requirements.Add(new MinimumAgeRequirement(18)));

Secure API Design Strategy (Recommended)

| Layer      | Responsibility      |
| ---------- | ------------------- |
| JWT        | Identity + claims   |
| Policy     | Authorization rules |
| Controller | Minimal logic       |
| Service    | Business logic      |

Common Authorization Mistakes

❌ Authorization in business logic only
❌ Using roles for everything
❌ Hardcoding permissions
❌ Not validating claims
❌ Overexposing sensitive data

Real-World Authorization Patterns

  • Admin Panel: Role + permission
  • Multi-Tenant SaaS: TenantId claim
  • Subscription-based apps: Plan claim
  • Enterprise apps: Department + policy

Security Best Practices

  • Use short-lived access tokens
  • Use refresh token rotation
  • Validate JWT issuer & audience
  • Avoid sensitive data in claims
  • Centralize policy definitions
0 Comments