Other 3xx codes
All HTTP status codes in ASP.NET Core
3xx Redirection
The resource is temporarily at another URL, given in Location. Clients may change POST to GET when following it.
In ASP.NET Core: Results.Redirect and ControllerBase.Redirect return it. Use 307 if the method must be kept.
The StatusCodes constant, HttpStatusCode enum name, reason phrase, class, and how EnsureSuccessStatusCode() and the standard resilience handler treat 302.
| Constant | StatusCodes.Status302Found |
|---|---|
| HttpStatusCode | HttpStatusCode.Found, HttpStatusCode.Redirect (aliases, same value) |
| Reason phrase | Kestrel sends Found |
| Class | 3xx, redirection |
| IsSuccessStatusCode | false |
| EnsureSuccessStatusCode() | throws HttpRequestException: Response status code does not indicate success: 302 (Found). |
| Standard resilience handler | does not retry it |
| HttpClient redirect | GET: followed, as GET. POST: followed, as GET. |
Results.StatusCode(StatusCodes.Status302Found)
Results.Problem(statusCode: StatusCodes.Status302Found, detail: "...")StatusCode(StatusCodes.Status302Found)
Problem(statusCode: StatusCodes.Status302Found, detail: "...")Checked on Kestrel: Results.Redirect(url), Results.LocalRedirect(url), ControllerBase.Redirect(url), ControllerBase.RedirectToAction return 302.
What Results.Problem(statusCode: 302) sends (with AddProblemDetails()), as application/problem+json:
{
"title": "Found",
"status": 302,
"traceId": "0HNA1B2C3D4E5:00000001"
}A controller's Problem(statusCode: 302) sends a different body, because MVC only fills type and title for codes in ApiBehaviorOptions.ClientErrorMapping:
{
"status": 302,
"traceId": "0HNA1B2C3D4E5:00000001"
}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.
Setup
app.MapGet("/api/admin", () => "ok").RequireAuthorization(p => p.RequireRole("admin"));Request
GET /api/admin HTTP/1.1
Cookie: <a signed-in user without the admin role>Response (recorded)
HTTP/1.1 302 Found
Location: http://localhost:5000/Account/AccessDenied?ReturnUrl=%2Fapi%2FadminThe cookie handler redirects forbidden requests to /Account/AccessDenied instead of answering 403.
Fix: Set options.Events.OnRedirectToAccessDenied to answer 403 for API paths.
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