Authorization logic is security-critical.
If it isn’t tested, it will break silently.
In this article, we’ll cover how to unit test and integration test authorization in ASP.NET Core, including roles, claims, policies, and custom handlers.
Why Test Authorization?
Authorization bugs can:
- Expose sensitive data
- Allow privilege escalation
- Break compliance rules
- Go unnoticed until production
👉 Testing ensures only the right users access the right resources.
What Should Be Tested?
| Layer | What to Test |
| ----------------- | ------------------------------ |
| Unit Tests | Policies, handlers, role logic |
| Integration Tests | Endpoint access |
| E2E (optional) | Full auth flow |
We’ll focus on Unit + Integration tests.
Testing Tools
- xUnit – test framework
- Moq – mocking dependencies
- Microsoft.AspNetCore.Mvc.Testing – integration tests
- TestServer / WebApplicationFactory
1️⃣ Unit Testing Authorization Policies
Example Policy
options.AddPolicy("FinanceOnly", policy =>
policy.RequireClaim("department", "finance"));Unit Test the Policy
[Fact]
public async Task FinanceOnlyPolicy_ShouldSucceed_ForFinanceUser()
{
var requirement = new ClaimsAuthorizationRequirement(
"department", new[] { "finance" });
var user = new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim("department", "finance")
}));
var context = new AuthorizationHandlerContext(
new[] { requirement }, user, null);
var handler = new ClaimsAuthorizationHandler();
await handler.HandleAsync(context);
Assert.True(context.HasSucceeded);
}2️⃣ Unit Testing Role-Based Authorization
Controller Example
[Authorize(Roles = "Admin")]
public IActionResult AdminOnly()
{
return Ok();
}Unit Test
[Fact]
public void User_With_Admin_Role_Should_Be_Authorized()
{
var user = new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Role, "Admin")
}, "TestAuth"));
Assert.True(user.IsInRole("Admin"));
}3️⃣ Unit Testing Custom Authorization Handlers
Custom Requirement
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int Age { get; }
public MinimumAgeRequirement(int age) => Age = age;
}Handler Test
[Fact]
public async Task AgeRequirement_Should_Succeed_When_Age_Is_Valid()
{
var requirement = new MinimumAgeRequirement(18);
var user = new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim("age", "20")
}));
var context = new AuthorizationHandlerContext(
new[] { requirement }, user, null);
var handler = new MinimumAgeHandler();
await handler.HandleAsync(context);
Assert.True(context.HasSucceeded);
}4️⃣ Integration Testing Authorization (Real API Calls)
Unit tests don’t verify middleware + routing + filters.
👉 That’s where integration tests shine.
Setting Up Integration Tests
Install Package
dotnet add package Microsoft.AspNetCore.Mvc.Testing
Custom WebApplicationFactory
public class TestAppFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"Test", options => { });
});
}
}Fake Authentication Handler
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock) { }
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var claims = new[]
{
new Claim(ClaimTypes.Role, "Admin"),
new Claim("department", "finance")
};
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");
return Task.FromResult(AuthenticateResult.Success(ticket));
}
}Integration Test Example
[Fact]
public async Task Admin_Endpoint_Should_Return_200_For_Admin()
{
var factory = new TestAppFactory();
var client = factory.CreateClient();
var response = await client.GetAsync("/admin/dashboard");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}Testing Unauthorized Access
[Fact]
public async Task Unauthorized_User_Should_Get_403()
{
var client = new WebApplicationFactory<Program>().CreateClient();
var response = await client.GetAsync("/admin/dashboard");
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}Best Practices for Authorization Testing
✅ Test positive & negative cases
✅ Test each policy separately
✅ Avoid real JWTs in unit tests
✅ Use fake auth handlers
✅ Test integration paths only where needed
What Not to Test
❌ Framework internals
❌ JWT encryption itself
❌ ASP.NET Core middleware logic
Recommended Test Coverage
| Feature | Coverage |
| --------------- | -------- |
| Roles | ✅ |
| Claims | ✅ |
| Policies | ✅ |
| Custom handlers | ✅ |
| API endpoints | ✅ |
Real-World Use Cases
- Admin panels
- Finance systems
- Healthcare apps
- Multi-tenant SaaS
- Enterprise portals