dotnet / dotnet/AspNetCore.Docs
API Endpoint Auth: Verify updated for .NET 10 - Freshness
- Dominant language
- C#
- Stars
- 13.1k
- Forks
- 24.6k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 97
Description
### Description
This article needs an update for .NET 10 in several areas.
#### Review: API endpoint authentication behavior article (.NET 10)
File: `aspnetcore/security/authentication/api-endpoint-auth.md`
Commit: `a70166e740ba50ca6b28e607ad26dd750fdf6882`
Line numbers refer to the commit above. The `[ApiController]` bullet (line 22) and the SignalR bullet (line 25) were verified accurate against the shipped source and need no change.
---
#### Incorrect and must fix, Pri 1
#### Line 52 — "non-breaking" claim
> `This behavior change introduced in .NET 10 is designed to be non-breaking for existing applications:`
This directly contradicts the sibling doc in the same repo, `aspnetcore/breaking-changes/10/cookie-authentication-api-endpoints.md`, which classifies the change as a behavioral change. Any existing app combining `[ApiController]` with cookie authentication that relied on a 302 to the login page changes behavior on upgrade.
**Fix:** Rename the H2 at line 50 from "Migration considerations" to "Breaking change considerations", replace the line 52 claim, and add an `` to the breaking-change article.
#### Lines 32 and 68 — "without redirects" and the `Location` assertion
> Line 32: `- **API endpoints**: Return 401 or 403 status codes without redirects`
>
> Line 68: `Assert.False(response.Headers.Location != null); // No redirect`
The handler sets `Location` and *then* the status code. The header is not suppressed:
```csharp
// src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs
if (IsAjaxRequest(context.Request) || IsCookieRedirectDisabledByMetadata(context.HttpContext))
{
context.Response.Headers.Location = context.RedirectUri;
context.Response.StatusCode = 401;
}
```
Line 32 is merely loose wording. Line 68 is outright false — the sample test as written would fail.
**Fix:** Change line 32 to "Return 401 or 403 status codes instead of a 302 redirect" and add a `[!NOTE]` stating that the `Location` header is still present. Rewrite line 68 to assert the header **is** present.
#### Line 23 — Minimal API detection criteria
> `- Minimal API endpoints registered with MapGet, MapPost, MapPut, MapDelete, etc.`
The registration verb is irrelevant. The metadata is added conditionally based on the handler's return type and request body:
```csharp
// src/Http/Http.Extensions/src/RequestDelegateFactory.cs
if (returnType == typeof(void) || typeof(IResult).IsAssignableFrom(returnType)) { return; }
if (returnType == typeof(string))
{
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(string), 200, PlaintextContentType));
}
else
{
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(returnType, 200, DefaultAcceptsAndProducesContentType));
if (factoryContext.JsonRequestBodyParameter is null)
{
builder.Metadata.Add(DisableCookieRedirectMetadata.Instance);
}
}
```
`MapGet("/x", () => "hello")` returns a string and void-returning handlers return early — both still **redirect**.
**Fix:** Adopt the accurate wording already used in the breaking-change doc — "Minimal API endpoints that read JSON request bodies or write JSON responses" — and add a separate bullet for endpoints using `TypedResults` return types.
#### Line 24 — "Endpoints that explicitly request JSON responses"
This implies runtime `Accept`-header content negotiation. Detection is entirely build-time metadata inference.
**Fix:** Delete the bullet; it is covered by the corrected line 23 bullets.
#### Lines 34–48 — "Configuring the behavior" section
The code block at lines 38–46 is a no-op that demonstrates nothing, and the guidance on line 48 (use `[Authorize]` with specific schemes or implement custom authentication handlers) is not the mechanism for controlling this behavior. The actual shipped opt-in/opt-out APIs appear nowhere in the article:
```csharp
// src/Http/Http.Extensions/src/CookieRedirectEndpointConventionBuilderExtensions.cs
public static TBuilder DisableCookieRedirect(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
{
builder.Add(b => b.Metadata.Add(DisableCookieRedirectMetadata.Instance));
return builder;
}
public static TBuilder AllowCookieRedirect(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
{
builder.Add(b => b.Metadata.Add(_allowCookieRedirectAttribute));
return builder;
}
```
There is also an `[AllowCookieRedirect]` attribute (`AttributeTargets.Method | AttributeTargets.Class`). Critically, `IAllowCookieRedirectMetadata` **always wins regardless of order** — a detail the article must state.
**Fix:** Replace lines 36–48 with working examples of `MapGroup(...).DisableCookieRedirect()`, `.AllowCookieRedirect()`, and the `[AllowCookieRedirect]` attribute on controllers.
#### Cross-file — `aspnetcore/breaking-changes/10/cookie-authentication-api-endpoints.md`, lines 13 and 108
> `Known API endpoints are identified using the new IApiEndpointMetadata ... interface`
`IApiEndpointMetadata` **does not exist in the shipped product** — searching `dotnet/aspnetcore` returns zero results. It was renamed before RTM to the `IDisableCookieRedirectMetadata` / `IAllowCookieRedirectMetadata` pair.
**Fix:** Correct both references. Add the convention-builder extensions and `AllowCookieRedirectAttribute` to the "Affected APIs" list at lines 106–110.
---
### Material gaps Pri 2
#### Missing global opt-out switch (insert after line 48)
A global `AppContext` switch restores the pre-.NET 10 behavior app-wide:
```csharp
// src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs
private static readonly bool _ignoreCookieRedirectMetadata =
AppContext.TryGetSwitch("Microsoft.AspNetCore.Authentication.Cookies.IgnoreRedirectMetadata", out var isEnabled) && isEnabled;
```
This is the cleanest escape hatch for large apps. The breaking-change doc also omits it — lines 40–104 there show only manual event overrides, which is far more work for the same result.
**Fix:** Document the switch in both files, including the `RuntimeHostConfigurationOption` MSBuild form.
#### Missing scope caveat (insert after line 32)
`OnRedirectToLogout` and `OnRedirectToReturnUrl` check only `IsAjaxRequest` — they do **not** call `IsCookieRedirectDisabledByMetadata`. Sign-out from an API endpoint still issues a 302. Only the challenge (401) and forbid (403) paths are affected by this change.
**Fix:** Add a note clarifying the change applies to challenge and forbid only, not sign-out or return-URL redirects.
---
#### Scope
Lines 16–70 need rewriting. Only the front matter shell, lines 22 and 25, and the Related topics list survive largely intact.
### Page URL
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/api-endpoint-auth?view=aspnetcore-10.0
### Content source URL
https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/security/authentication/api-endpoint-auth.md
### Document ID
202ccb1a-4a6a-aa0d-9279-d2556a46294b
### Platform Id
bde9cd94-8998-5312-1ed9-3d37c49986c5
### Article author
@wadepickett
### Metadata
* ID: 202ccb1a-4a6a-aa0d-9279-d2556a46294b
* PlatformId: bde9cd94-8998-5312-1ed9-3d37c49986c5
* Service: **aspnet-core**
* Sub-service: **security**
Contributor guide
Assessment
This issue has not been assessed yet.