ASP0026: [Authorize] is overridden by [AllowAnonymous] from "farther away"

Value
Rule ID ASP0026
Category Usage
Fix is breaking or non-breaking Non-breaking

Cause

It seems intuitive that an [Authorize] attribute placed "closer" to an MVC action than an [AllowAnonymous] attribute would override the [AllowAnonymous] attribute and force authorization. However, this is not necessarily the case. What does matter is the relative order of the attributes.

The following code shows examples where a closer [Authorize] attribute gets overridden by an [AllowAnonymous] attribute that is farther away.

[AllowAnonymous]
public class MyController
{
    [Authorize] // Overridden by the [AllowAnonymous] attribute on the class
    public IActionResult Private() => null;
}
[AllowAnonymous]
public class MyControllerAnon : ControllerBase
{
}

[Authorize] // Overridden by the [AllowAnonymous] attribute on MyControllerAnon
public class MyControllerInherited : MyControllerAnon
{
}

public class MyControllerInherited2 : MyControllerAnon
{
    [Authorize] // Overridden by the [AllowAnonymous] attribute on MyControllerAnon
    public IActionResult Private() => null;
}
[AllowAnonymous]
[Authorize] // Overridden by the preceding [AllowAnonymous]
public class MyControllerMultiple : ControllerBase
{
}

Rule description

Warning that an [Authorize] attribute is overridden by an [AllowAnonymous] attribute from "farther away."

How to fix violations

The correct action to take if you see this warning depends on the intention behind the attributes. The farther away [AllowAnonymous] attribute should be removed if it's unintentionally exposing the endpoint to anonymous users. If the [AllowAnonymous] attribute was intended to override a closer [Authorize] attribute, you can repeat the [AllowAnonymous] attribute after the [Authorize] attribute to clarify the intent.

[AllowAnonymous]
public class MyController
{
    // This produces no warning because the second, "closer" [AllowAnonymous]
    // clarifies that [Authorize] is intentionally overridden.
    // Specifying AuthenticationSchemes can still be useful
    // for endpoints that allow but don't require authenticated users.
    [Authorize(AuthenticationSchemes = "Cookies")]
    [AllowAnonymous]
    public IActionResult Privacy() => null;
}

When to suppress warnings

The severity level of this diagnostic is Information. You can suppress warnings if your intention is to override the [Authorize] attribute. However, we recommend that you make the intent clear by repeating the [AllowAnonymous] attribute after the [Authorize] attribute.