HTTP 302 Found
A 302 sends the client to the Location URL for this request only. The original URL stays authoritative, so clients shouldn't update bookmarks, and caches don't store the redirect unless Cache-Control or Expires explicitly allows it.
302 Found
The resource is temporarily at a different URL; keep using the original URL for future requests.
Who fixes it: Server config. Clients follow it automatically. Problems come from servers using 302 where a 301, 307 or 401 was meant.
What 302 means
The name "Found" is a leftover from HTTP/1.0, where it was "Moved Temporarily". As with 301, user agents may change a POST to a GET when following it, and browsers do. That ambiguity is why HTTP/1.1 added 303 See Other (always switch to GET) and 307 Temporary Redirect (never switch).
302 is the default in many frameworks: Express res.redirect(), PHP header('Location: ...'), Flask redirect() and Django redirect() all send 302 unless told otherwise.
Source: RFC 9110 §15.4.3.
Typical reasons you get a 302
- Login walls: an unauthenticated request to
/dashboardis redirected to/login?next=/dashboard. For an API this is a bug, because a JSON client wants a 401, not an HTML login page. - Post/Redirect/Get after a form submission. 303 is the precise code; 302 is what most frameworks send.
- Geo, language or device redirects (
/to/en-gb/). - Temporary maintenance or campaign redirects.
- A permanent move implemented with the framework default. This is the most common SEO mistake involving 302.
How to debug a 302
See the redirect with curl
curl doesn't follow redirects unless you pass -L, so you see the 302 and its Location.
curl -sI https://example.com/dashboard
HTTP/2 302
location: /login?next=%2Fdashboard
# Follow it and print every hop
curl -sIL https://example.com/dashboard | grep -iE '^(HTTP|location)'Express: be explicit, and send 401 to API clients
Don't rely on the 302 default for permanent moves, and don't redirect API calls to an HTML login page.
// Permanent move
app.get('/old', (req, res) => res.redirect(301, '/new'));
// Auth: redirect browsers, 401 for API calls
function requireAuth(req, res, next) {
if (req.user) return next();
if (req.path.startsWith('/api/')) {
return res.status(401).json({ error: 'unauthenticated' });
}
res.redirect(302, `/login?next=${encodeURIComponent(req.originalUrl)}`);
}Detect silent redirects in fetch()
fetch() follows redirects without telling you. res.redirected and res.url reveal it. With redirect: 'manual' a browser gives you an opaque response with status 0, so you can't read Location from JavaScript.
const res = await fetch('/api/me');
if (res.redirected) {
console.warn('Redirected to', res.url); // often a login page returning HTML
}Headers that matter with 302
- Location
- The temporary target.
- Cache-Control
- A 302 is only cached if explicitly allowed. Send
Cache-Control: no-storeon redirects that depend on login state.
302 vs similar status codes
- 301 Moved Permanently: Permanent. Clients and search engines move to the new URL.
- 307 Temporary Redirect: Also temporary, but the method and body must be kept. Use it when a POST must stay a POST.
- 303 See Other: Always fetch the target with GET. The precise code for Post/Redirect/Get.
SEO impact of 302
Google treats a 302 as a weak signal that the target should be canonical, so the original URL usually stays in the index. That's correct for genuinely temporary moves. If the move is permanent, switch to 301 or 308; Google may eventually treat a long-lived 302 as permanent, but you're leaving the decision to it.
Related status codes
301Moved Permanently
The resource has a new permanent URL, given in the Location header.
307Temporary Redirect
Temporarily redirected: repeat the same request, with the same method and body, at the Location URL.
308Permanent Redirect
Permanently moved: repeat this and future requests at the Location URL without changing the method.
401Unauthorized
The request lacks valid authentication credentials for the target resource.
Looking for another code? Search the full HTTP status codes list, or read which code your API should return in the REST API status codes guide.
Learn more
HTTP Status Codes for REST APIs: 200 vs 201 vs 204, 400 vs 422 vs 429
A practical guide to choosing the right HTTP status code in REST API design. Covers the most confusing pairs: 200 vs 201, 400 vs 422, 401 vs 403, and when to use 503 vs 429.
REST API Design Best Practices: A Practical Guide
The conventions that make REST APIs intuitive and consistent. Covers URL design, HTTP methods, status codes, versioning, pagination, and error responses.
CORS Explained: Why It Happens and How to Fix It
CORS errors happen when a browser blocks a request to a different origin. Learn how the Same-Origin Policy works, what preflight requests are, and how to configure CORS correctly in Express, FastAPI, and Nginx.
Frequently Asked Questions
What is the difference between 302 and 307?▾
Both are temporary. With 302, browsers change a POST to a GET when following the redirect. With 307 the method and body must stay the same. Use 307 when a redirected POST, PUT or DELETE has to reach the new URL intact.
Is a 302 redirect bad for SEO?▾
Not when the redirect really is temporary. It becomes a problem when a permanent move is left on 302, because Google may keep showing the old URL. Use 301 or 308 for permanent moves.
Why does my API return 302 instead of 401?▾
Usually session-based auth set up for web pages, such as Spring Security form login, ASP.NET Core cookie authentication or Passport's failureRedirect, redirects every unauthenticated request to the login page. Configure it to return 401 for API routes or for requests that send Accept: application/json.