Skip to content
Authorization

Authorization

By default AddHmac authenticates any request that verifies against any registered policy. That is often not enough: if you hold one policy for a partner and another for an internal service, “verified” does not mean “allowed here”.

Four ways to narrow it, from most direct to most composable.

The attribute

[HmacAuthenticate(Policy = "HmacPolicy", Scheme = "HmacScheme")]
public class HomeController : Controller
{
}

As an authorization requirement

HmacAuthenticateAttribute is also an IAuthorizationRequirement, so it can go straight into a policy. HmacAuthorizationHandler is registered to handle it.

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireHmac", policy =>
        policy.AddRequirements(new HmacAuthenticateAttribute
        {
            Policy = "HmacPolicy",
            Scheme = "HmacScheme"
        }));
});

The builder extensions

RequireHmacPolicy and RequireHmacScheme add the same requirements more readably, and compose with everything else on AuthorizationPolicyBuilder:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireHmac", policy =>
    {
        policy.RequireHmacPolicy("HmacPolicy");
        policy.RequireHmacScheme("HmacScheme");
    });
});

Or both at once:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireHmac", policy =>
    {
        policy.RequireHmacAuthentication("HmacPolicy", "HmacScheme");
    });
});

Then use it as you would any authorization policy:

[Authorize("RequireHmac")]
public class PaymentsController : ControllerBase
{
}

Claims

When a request authenticates with a scheme, every header that scheme names is added to the ClaimsPrincipal. The claim type is whatever the scheme declared, or the header’s own name if it declared none — so scheme.AddHeader("X-UserId", ClaimTypes.NameIdentifier) makes User.FindFirst(ClaimTypes.NameIdentifier) return the signed value.

Those values are covered by the signature, which is what makes them safe to authorize on. An unsigned header is just a header. See schemes.