From e5700a53a64444f4c6075af9d306b6de91bf126b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 18:45:19 +0000 Subject: [PATCH 1/2] Initial plan From 6bd5393ecb2789a564f4c9095ec2dfbfc5bd69a7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 18:50:06 +0000 Subject: [PATCH 2/2] Clarify ASP0026 warning: AllowAnonymous allows but doesn't require authentication Co-authored-by: tdykstra <1569635+tdykstra@users.noreply.github.com> --- aspnetcore/diagnostics/asp0026.md | 21 ++++++++++++++----- .../aspnetcore-9/includes/asp0026.md | 9 ++++++-- 2 files changed, 23 insertions(+), 7 deletions(-) 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;