diff --git a/docs/core/compatibility/10.0.md b/docs/core/compatibility/10.0.md index 6f0dcd3ba032b..9b537847d39dd 100644 --- a/docs/core/compatibility/10.0.md +++ b/docs/core/compatibility/10.0.md @@ -2,7 +2,7 @@ title: Breaking changes in .NET 10 titleSuffix: "" description: Navigate to the breaking changes in .NET 10. -ms.date: 06/05/2025 +ms.date: 08/08/2025 ai-usage: ai-assisted no-loc: [Blazor, Razor, Kestrel] --- @@ -17,8 +17,9 @@ If you're migrating an app to .NET 10, the breaking changes listed here might af ## ASP.NET Core -| Title | Type of change | Introduced version | -|-------|---------------------|--------------------| +| Title | Type of change | Introduced version | +|-------|-------------------|--------------------| +| [Cookie login redirects disabled for known API endpoints](aspnet-core/10/cookie-authentication-api-endpoints.md) | Behavioral change | Preview 7 | | [Deprecation of WithOpenApi extension method](aspnet-core/10/withopenapi-deprecated.md) | Source incompatible | Preview 7 | | [Exception diagnostics suppressed when TryHandleAsync returns true](aspnet-core/10/exception-handler-diagnostics-suppressed.md) | Behavioral change | Preview 7 | | [IActionContextAccessor and ActionContextAccessor are obsolete](aspnet-core/10/iactioncontextaccessor-obsolete.md) | Source incompatible/behavioral change | Preview 7 | diff --git a/docs/core/compatibility/aspnet-core/10/cookie-authentication-api-endpoints.md b/docs/core/compatibility/aspnet-core/10/cookie-authentication-api-endpoints.md new file mode 100644 index 0000000000000..bdc3b2ce1935e --- /dev/null +++ b/docs/core/compatibility/aspnet-core/10/cookie-authentication-api-endpoints.md @@ -0,0 +1,110 @@ +--- +title: "Cookie login redirects are disabled for known API endpoints" +description: "Learn about the breaking change in ASP.NET Core 10 where cookie authentication no longer redirects to login or access denied URIs for known API endpoints." +ms.date: 08/08/2025 +ai-usage: ai-assisted +ms.custom: https://github.com/aspnet/Announcements/issues/525 +--- + +# Cookie login redirects are disabled for known API endpoints + +By default, unauthenticated and unauthorized requests made to known API endpoints protected by cookie authentication now result in 401 and 403 responses rather than redirecting to a login or access-denied URI. + +Known API [endpoints](/aspnet/core/fundamentals/routing) are identified using the new `IApiEndpointMetadata` interface, and metadata implementing the new interface has been added automatically to the following: + +- [`[ApiController]`](xref:Microsoft.AspNetCore.Mvc.ApiControllerAttribute) endpoints. +- Minimal API endpoints that read JSON request bodies or write JSON responses. +- Endpoints using return types. +- SignalR endpoints. + +## Version introduced + +.NET 10 Preview 7 + +## Previous behavior + +Previously, the cookie authentication handler redirected unauthenticated and unauthorized requests to a login or access-denied URI by default for all requests other than [XMLHttpRequests (XHRs)](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest). + +## New behavior + +Starting in .NET 10, unauthenticated and unauthorized requests made to known API endpoints result in 401 and 403 responses rather than redirecting to a login or access-denied URI. XHRs continue to result in 401 and 403 responses regardless of the target endpoint. + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +This change was highly requested. Redirecting unauthenticated requests to a login page doesn't usually make sense for API endpoints, which typically rely on 401 and 403 status codes rather than HTML redirects to communicate auth failures. + +## Recommended action + +If you want to always redirect to the login and access-denied URIs for unauthenticated or unauthorized requests regardless of the target endpoint or whether the source of the request is an XHR, you can override and as follows: + +```csharp +builder.Services.AddAuthentication() + .AddCookie(options => + { + options.Events.OnRedirectToLogin = context => + { + context.Response.Redirect(context.RedirectUri); + return Task.CompletedTask; + }; + + options.Events.OnRedirectToAccessDenied = context => + { + context.Response.Redirect(context.RedirectUri); + return Task.CompletedTask; + }; + }); +``` + +If you want to revert to the exact previous behavior that avoids redirecting for only XHRs, you can override the events with this slightly more complicated logic: + +```csharp +builder.Services.AddAuthentication() + .AddCookie(options => + { + bool IsXhr(HttpRequest request) + { + return string.Equals(request.Query[HeaderNames.XRequestedWith], "XMLHttpRequest", StringComparison.Ordinal) || + string.Equals(request.Headers.XRequestedWith, "XMLHttpRequest", StringComparison.Ordinal); + } + + options.Events.OnRedirectToLogin = context => + { + if (IsXhr(context.Request)) + { + context.Response.Headers.Location = context.RedirectUri; + context.Response.StatusCode = 401; + } + else + { + context.Response.Redirect(context.RedirectUri); + } + + return Task.CompletedTask; + }; + + options.Events.OnRedirectToAccessDenied = context => + { + if (IsXhr(context.Request)) + { + context.Response.Headers.Location = context.RedirectUri; + context.Response.StatusCode = 403; + } + else + { + context.Response.Redirect(context.RedirectUri); + } + + return Task.CompletedTask; + }; + }); +``` + +## Affected APIs + +- `Microsoft.AspNetCore.Http.Metadata.IApiEndpointMetadata` +- +- diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index 98f4e16fac2c1..0b6981cd06512 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -10,6 +10,8 @@ items: href: 10.0.md - name: ASP.NET Core items: + - name: Cookie login redirects disabled for known API endpoints + href: aspnet-core/10/cookie-authentication-api-endpoints.md - name: Deprecation of WithOpenApi extension method href: aspnet-core/10/withopenapi-deprecated.md - name: Exception diagnostics suppressed when TryHandleAsync returns true