Other 4xx codes
All HTTP status codes in ASP.NET Core
4xx Client error
The request lacks valid authentication. The response must include a WWW-Authenticate header saying how to authenticate. Despite the name, it means unauthenticated.
In ASP.NET Core: Let the authentication middleware send it: [Authorize] or RequireAuthorization() with no or an invalid credential.
The StatusCodes constant, HttpStatusCode enum name, reason phrase, class, and how EnsureSuccessStatusCode() and the standard resilience handler treat 401.
| Constant | StatusCodes.Status401Unauthorized |
|---|---|
| HttpStatusCode | HttpStatusCode.Unauthorized |
| Reason phrase | Kestrel sends Unauthorized |
| Class | 4xx, client error |
| IsSuccessStatusCode | false |
| EnsureSuccessStatusCode() | throws HttpRequestException: Response status code does not indicate success: 401 (Unauthorized). |
| Standard resilience handler | does not retry it |
TypedResults.Unauthorized()
Results.StatusCode(StatusCodes.Status401Unauthorized)
Results.Problem(statusCode: StatusCodes.Status401Unauthorized, detail: "...")Unauthorized()
Unauthorized(value)
StatusCode(StatusCodes.Status401Unauthorized)
Problem(statusCode: StatusCodes.Status401Unauthorized, detail: "...")What Results.Problem(statusCode: 401) sends (with AddProblemDetails()), as application/problem+json:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
"title": "Unauthorized",
"status": 401,
"traceId": "0HNA1B2C3D4E5:00000001"
}A controller's Problem(statusCode: 401) sends the same body.
A bare StatusCode(401) in an [ApiController] also gets a ProblemDetails body automatically; Results.StatusCode(401) in a minimal API sends an empty body unless you add UseStatusCodePages().
Setup
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(...);
app.MapGet("/secure", () => "ok").RequireAuthorization();Request
GET /secure HTTP/1.1Response (recorded)
HTTP/1.1 401 Unauthorized
Www-Authenticate: BearerNo Authorization header: the bearer handler challenges with 401 and a bare WWW-Authenticate: Bearer.
Setup
// same as aboveRequest
GET /secure HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjF9.xResponse (recorded)
HTTP/1.1 401 Unauthorized
Www-Authenticate: Bearer error="invalid_token", error_description="The signature key was not found"The reason is in the WWW-Authenticate header's error_description. Our JWT decoder explains each one.
Setup
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
app.MapGet("/api/secure", () => "ok").RequireAuthorization();Request
GET /api/secure HTTP/1.1
(no cookie)Response (recorded)
HTTP/1.1 302 Found
Location: http://localhost:5000/Account/Login?ReturnUrl=%2Fapi%2FsecureThe cookie handler challenges with a redirect to /Account/Login, not a 401. A JavaScript or mobile client then follows it and gets an HTML login page, or a 404 if you have none.
Fix: For APIs, set options.Events.OnRedirectToLogin = ctx => { ctx.Response.StatusCode = 401; return Task.CompletedTask; }, or use a bearer token scheme.
Every response on this page was recorded from ASP.NET Core 10.0.12 on Kestrel in the Production environment; the HttpClient rows come from .NET 10.0.12 and Microsoft.Extensions.Http.Resilience 10.10.0.
All HTTP status codes in ASP.NET Core