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
- 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