diff --git a/aspnetcore/diagnostics/asp0026.md b/aspnetcore/diagnostics/asp0026.md index bf7e7c51ed18..ddca3fe8ad8c 100644 --- a/aspnetcore/diagnostics/asp0026.md +++ b/aspnetcore/diagnostics/asp0026.md @@ -1,10 +1,11 @@ --- title: "ASP0026: Analyzer to warn when [Authorize] is overridden by [AllowAnonymous] from 'farther away'" -ms.date: 03/27/2025 -description: "Learn about analysis rule ASP0026: [Authorize] is overridden by [AllowAnonymous] from 'farther away'" +ai-usage: ai-assisted author: tdykstra +description: "Learn about analysis rule ASP0026: [Authorize] is overridden by [AllowAnonymous] from 'farther away'" monikerRange: '>= aspnetcore-9.0' ms.author: tdykstra +ms.date: 11/06/2025 uid: diagnostics/asp0026 --- # ASP0026: `[Authorize]` is overridden by `[AllowAnonymous]` from "farther away" @@ -19,6 +20,9 @@ uid: diagnostics/asp0026 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. +> [!NOTE] +> The `[AllowAnonymous]` attribute doesn't disable authentication entirely. When credentials are sent to an endpoint with `[AllowAnonymous]`, the endpoint still authenticates those credentials and establishes the user's identity. The `[AllowAnonymous]` attribute only means that authentication is **not required**—the endpoint will run as anonymous only when no credentials are provided. This behavior can be useful for endpoints that need to work for both authenticated and anonymous users. + The following code shows examples where a closer `[Authorize]` attribute gets overridden by an `[AllowAnonymous]` attribute that is farther away. ```csharp @@ -58,7 +62,12 @@ public class MyControllerMultiple : ControllerBase ## Rule description -Warning that an `[Authorize]` attribute is overridden by an `[AllowAnonymous]` attribute from "farther away." +This warning indicates that an `[Authorize]` attribute is overridden by an `[AllowAnonymous]` attribute from "farther away." When `[AllowAnonymous]` takes precedence, the endpoint doesn't require authentication but still accepts and processes credentials if they're provided. This means: + +- If a request includes authentication credentials, the endpoint authenticates the user and makes their identity available. +- If a request doesn't include credentials, the endpoint allows anonymous access. + +This behavior might unintentionally expose endpoints that were meant to require authentication. ## How to fix violations @@ -70,8 +79,10 @@ 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. + // Specifying AuthenticationSchemes can be useful for endpoints that + // allow but don't require authenticated users. When credentials are sent, + // they will be authenticated; when no credentials are sent, the endpoint + // allows anonymous access. [Authorize(AuthenticationSchemes = "Cookies")] [AllowAnonymous] public IActionResult Privacy() => null; diff --git a/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md b/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md index 6985c4b985ad..ceef60e60e3a 100644 --- a/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md +++ b/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md @@ -2,6 +2,9 @@ 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. +> [!NOTE] +> The `[AllowAnonymous]` attribute doesn't disable authentication entirely. When credentials are sent to an endpoint with `[AllowAnonymous]`, the endpoint still authenticates those credentials and establishes the user's identity. The `[AllowAnonymous]` attribute only means that authentication is **not required**—the endpoint will run as anonymous only when no credentials are provided. This behavior can be useful for endpoints that need to work for both authenticated and anonymous users. + The following code shows examples where a closer `[Authorize]` attribute gets overridden by an `[AllowAnonymous]` attribute that is farther away. ```csharp @@ -53,8 +56,10 @@ 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. + // Specifying AuthenticationSchemes can be useful for endpoints that + // allow but don't require authenticated users. When credentials are sent, + // they will be authenticated; when no credentials are sent, the endpoint + // allows anonymous access. [Authorize(AuthenticationSchemes = "Cookies")] [AllowAnonymous] public IActionResult Privacy() => null;