Skip to main content

How to Authorize in ASP.NET API using Authorization Policy with Requirements and Handler

· 2 min read
Adnan Rafiq
Start and Finish Image

Image by @claybanks

Authorization Policy

Authorizing the resource access is essential part of any API. The .NET provides you a perfect mental model which is easier to reason about. It has this flow:

  1. What is the name of your policy as string.
  2. What requirement the user must satisfy to qualify which implements the IAuthorizationRequirement interface.
  3. What is your handler responsible to evaluate, which inherits the AuthorizationHandler<UniqueIdHeaderRequirement> and register it.

Then Authorize attribute allows you to set a policy name when used on controller or action method. But if you are fan of Minimal API then fluent style is the way to go using RequireAuthorization.

How to define Authorization Policy?

The AuthorizationOptions allows you to add policies with requirements using the AddAuthorization. Once the policy is defined and configured, it can be applied to the end point referred as resource.

Authorize using a Policy to verify that http header exists

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;

services.AddSingleton<IAuthorizationHandler, UniqueIdHeaderRequirement.UniqueIdHeaderRequirementAuthorizationHandler>();
// Required otherwise failure of auth handler will throw exception
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
services.AddAuthorization(options =>
{
options.InvokeHandlersAfterFailure = false;
options.AddPolicy("VerifyXUniqueIdHeader",
policyBuilder => {
policyBuilder.AddRequirements(new UniqueIdHeaderRequirement());
});
});
services.AddRouting();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(routeBuilder =>
{
//Fluent style
routeBuilder.MapGet("/", () => Results.Ok()).RequireAuthorization("VerifyXUniqueIdHeader");
//Attribute style - Same be done MVC controller or action
routeBuilder.MapGet("/hello", [Authorize(Policy = "VerifyXUniqueIdHeader")]() => Results.Ok());
});

app.Run();

internal class UniqueIdHeaderRequirement : IAuthorizationRequirement //IAuthorizationRequirement is a marker interface
{
// Handler gets called when the user is trying to access the resource.
internal class UniqueIdHeaderRequirementAuthorizationHandler : AuthorizationHandler<UniqueIdHeaderRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
UniqueIdHeaderRequirement requirement)
{
//for mvc filter context cast it to - AuthorizationFilterContext
if (context.Resource is HttpContext httpContext && !httpContext.Request.Headers.ContainsKey("x-unique-id"))
{
context.Fail();
return Task.CompletedTask;
}

context.Succeed(requirement);
return Task.CompletedTask;
}
}
}

Feedback

I would love to hear your feedback, feel free to share it on Twitter.