|
| 1 | +--- |
| 2 | +title: API endpoint authentication behavior in ASP.NET Core |
| 3 | +author: wadepickett |
| 4 | +description: Learn how ASP.NET Core 10 and later handles authentication failures for API endpoints using cookie authentication. |
| 5 | +ai-usage: ai-assisted |
| 6 | +monikerRange: '>= aspnetcore-10.0' |
| 7 | +ms.author: wpickett |
| 8 | +ms.date: 08/06/2025 |
| 9 | +uid: security/authentication/api-endpoint-auth |
| 10 | +--- |
| 11 | + |
| 12 | +# API endpoint authentication behavior in ASP.NET Core |
| 13 | + |
| 14 | +:::moniker range=">= aspnetcore-10.0" |
| 15 | + |
| 16 | +Starting with ASP.NET Core 10, the framework introduces a significant improvement in how authentication failures are handled for API endpoints when using cookie authentication. This change addresses the common issue where API endpoints would redirect unauthenticated requests to login pages, which is inappropriate for programmatic API access. |
| 17 | + |
| 18 | +## The problem |
| 19 | + |
| 20 | +In previous versions of ASP.NET Core, when using cookie authentication, all unauthenticated requests would trigger a redirect to the configured login page. This behavior was problematic for API endpoints because: |
| 21 | + |
| 22 | +- API clients don't expect HTML login pages |
| 23 | +- Redirects return 302 status codes instead of proper 401/403 codes |
| 24 | +- API clients need clear HTTP status codes to handle authentication failures appropriately |
| 25 | + |
| 26 | +## The solution in ASP.NET Core 10 |
| 27 | + |
| 28 | +ASP.NET Core 10 automatically detects known API endpoints and modifies the authentication behavior: |
| 29 | + |
| 30 | +- **Web pages**: Continue to redirect to login pages as before |
| 31 | +- **API endpoints**: Return appropriate 401 (Unauthorized) or 403 (Forbidden) status codes without redirects |
| 32 | + |
| 33 | +## Which endpoints are considered API endpoints? |
| 34 | + |
| 35 | +The framework automatically identifies the following as API endpoints: |
| 36 | + |
| 37 | +- Controllers decorated with `[ApiController]` attribute |
| 38 | +- Minimal API endpoints registered with `MapGet`, `MapPost`, `MapPut`, `MapDelete`, etc. |
| 39 | +- Endpoints that explicitly request JSON responses |
| 40 | +- SignalR hubs and endpoints |
| 41 | + |
| 42 | +## Behavior differences |
| 43 | + |
| 44 | +### Before ASP.NET Core 10 |
| 45 | + |
| 46 | +```http |
| 47 | +GET /api/secure-data HTTP/1.1 |
| 48 | +Host: example.com |
| 49 | +
|
| 50 | +HTTP/1.1 302 Found |
| 51 | +Location: /Account/Login?ReturnUrl=%2Fapi%2Fsecure-data |
| 52 | +``` |
| 53 | + |
| 54 | +### ASP.NET Core 10 and later |
| 55 | + |
| 56 | +```http |
| 57 | +GET /api/secure-data HTTP/1.1 |
| 58 | +Host: example.com |
| 59 | +
|
| 60 | +HTTP/1.1 401 Unauthorized |
| 61 | +WWW-Authenticate: Cookie |
| 62 | +``` |
| 63 | + |
| 64 | +## Configuring the behavior |
| 65 | + |
| 66 | +While the default behavior works for most scenarios, you can customize it if needed: |
| 67 | + |
| 68 | +```csharp |
| 69 | +builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) |
| 70 | + .AddCookie(options => |
| 71 | + { |
| 72 | + options.LoginPath = "/Account/Login"; |
| 73 | + // The framework automatically handles API endpoints |
| 74 | + // No additional configuration needed |
| 75 | + }); |
| 76 | +``` |
| 77 | + |
| 78 | +If you need to override the automatic detection for specific endpoints, you can use the `[Authorize]` attribute with specific authentication schemes or implement custom authentication handlers. |
| 79 | + |
| 80 | +## Migration considerations |
| 81 | + |
| 82 | +This change is designed to be non-breaking for existing applications: |
| 83 | + |
| 84 | +- **Web applications**: Continue to work as before with login page redirects |
| 85 | +- **Mixed applications**: API endpoints get proper status codes while web pages get redirects |
| 86 | +- **API-only applications**: Benefit from proper HTTP status codes without additional configuration |
| 87 | + |
| 88 | +### Testing your API endpoints |
| 89 | + |
| 90 | +After upgrading to ASP.NET Core 10, verify that your API endpoints return appropriate status codes: |
| 91 | + |
| 92 | +```csharp |
| 93 | +[Test] |
| 94 | +public async Task UnauthorizedApiRequest_Returns401() |
| 95 | +{ |
| 96 | + var response = await client.GetAsync("/api/secure-data"); |
| 97 | + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); |
| 98 | + Assert.False(response.Headers.Location != null); // No redirect |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +## Related topics |
| 103 | + |
| 104 | +- <xref:security/authentication/cookie> |
| 105 | +- <xref:web-api/index> |
| 106 | +- <xref:fundamentals/minimal-apis/responses> |
| 107 | +- <xref:signalr/authn-and-authz> |
| 108 | + |
| 109 | +:::moniker-range-end |
0 commit comments