A page never loads and the logs show a long chain of 30x responses. How do HTTP clients detect and stop redirect loops, and what are the usual server-side causes?
answer
- No protocol limit - clients cap hops (browsers ~20, curl 30)
- Count hops, do not just detect repeated URLs (auth flows revisit)
- X-Forwarded-Proto ignored = http/https loop
- Trailing-slash and www/apex rules fighting
- Login loop = Set-Cookie never comes back as Cookie
basics
~20 sHTTP defines no loop limit, so clients impose a maximum hop count - typically 20 in browsers, 30 in curl, and configurable in libraries - and abort with a too-many-redirects error. Typical causes: https-redirect rules behind a TLS-terminating proxy, trailing-slash rewrites fighting each other, and login redirects where the session cookie never sticks.
solid answer
~60 sThere is no protocol-level loop detection. Each client enforces its own **maximum redirect count** (browsers around 20, curl 30 via `--max-redirs`, most libraries configurable and some defaulting to no following at all) and fails with an error such as `ERR_TOO_MANY_REDIRECTS`. Counting hops is preferred over tracking visited URLs, because a legitimate chain can revisit a URL with different cookies, and an attacker can build an infinite chain of distinct URLs. The usual root causes: - **Scheme loop.** The origin redirects http to https, but a TLS-terminating proxy forwards the request as plain http and the app ignores `X-Forwarded-Proto`, so every request looks like http and redirects forever. - **Trailing-slash war.** One rule appends a slash, another strips it. - **Auth loop.** The app redirects to a login page, login redirects back, but the session cookie is never accepted - `Secure` on an http origin, wrong `Domain`, or `SameSite` blocking it on a cross-site POST callback. - **Edge versus origin.** A CDN rule and an origin rule each canonicalise to a different host. Diagnose with `curl -sIL`: print every hop's status, `Location`, and `Set-Cookie`, and the loop's shape identifies the cause immediately.
code
bash · 1 linecurl -sIL --max-redirs 10 https://example.com/app | grep -Ei '^(HTTP/|location:|set-cookie:)'go deeper
Know that clients stop after a maximum number of redirects and report a too-many-redirects error, and that two rules pointing at each other is the usual cause.
Explain hop counting versus URL tracking and name concrete causes: http/https rules behind a proxy, trailing-slash conflicts, login loops.
Drive the diagnosis - inspect every hop's status, Location and Set-Cookie, identify the loop period, reproduce with forwarded headers - and cap redirects in server-side clients.
Own canonicalisation as an architectural decision: one place decides scheme, host and trailing slash; everything downstream is idempotent; permanent redirects are treated as hard-to-revoke during migrations.
## Why clients, not the protocol, stop loops HTTP has no notion of a redirect chain. Each 3xx is an independent response, and the client is free to follow it or not. Since a server can trivially point back to a URL that redirects again, every client that follows redirects automatically must impose its own bound. **Hop counting** is the standard mechanism: keep a counter, increment per redirect, abort when it exceeds the limit. Common limits are ~20 for browsers, 30 for curl (`--max-redirs`, where -1 means unlimited), and library-specific values elsewhere; some clients default to *not* following at all, which is a safe default for server-side code. Errors surface as `ERR_TOO_MANY_REDIRECTS` in browsers or curl error 47. **Visited-URL tracking** is sometimes added on top, but it cannot be the primary defence: a chain can walk through unbounded distinct URLs (`/a/1` -> `/a/2` -> ...), and a legitimate flow may revisit the same URL with different state - the auth dance of app -> IdP -> app is exactly that. Aborting on the first repeat would break real logins. ## The recurring server-side causes **Proxy scheme confusion.** The most common by far. The app has a rule: "if the request is not https, redirect to the https URL." A load balancer terminates TLS and speaks plain http to the app. The app sees http, redirects to https, the browser re-requests over https, the balancer again forwards http - and around it goes. The fix is to make the app trust `X-Forwarded-Proto` (or the `Forwarded` header) from trusted proxies only, and to configure the framework's forwarded-headers support rather than sniffing the socket. **Canonicalisation conflicts.** A rewrite rule that adds a trailing slash combined with a framework that strips it; a www-to-apex rule at the CDN with an apex-to-www rule at the origin; a locale redirect that infers a language, redirects to `/en/`, and then re-infers on the new path. Each component is individually correct; composed they oscillate. This is a systems bug, so the fix is to decide on one canonicalisation point - usually the edge - and make everything downstream idempotent. **Authentication loops.** The app finds no session, redirects to `/login`; login authenticates and redirects back; the app still finds no session. The cookie is the suspect: `Secure` set on a plain-http environment, `Domain` set to the wrong host, `SameSite=Lax` or `Strict` dropping the cookie on a cross-site callback (a POST from an identity provider is cross-site), a cookie larger than the server's header limit, or clock skew making it instantly expired. The tell is a `Set-Cookie` in the chain that never reappears as a `Cookie` on the next hop. **Stale caching.** A permanent redirect (which browsers cache aggressively) recorded during a misconfiguration keeps looping for users long after the server is fixed, because the client never asks again. This is why permanent redirects deserve caution during migrations and why the reproduction should be tried in a fresh profile or with cache disabled. ## Diagnosis procedure 1. `curl -sIL -o /dev/null -w '%{url_effective}\n' <url>` to see where it ends; then `curl -sIL <url>` to print every hop with status, `Location` and `Set-Cookie`. 2. Read the loop's period. Two-URL oscillation means two conflicting rules. A single URL redirecting to itself means a condition that never becomes true - almost always scheme or cookie state. 3. Replay a hop with the headers the proxy actually sends (`-H 'X-Forwarded-Proto: https'`) to confirm a scheme-detection bug. 4. Check whether the loop is client-specific: browsers, curl and server-side libraries differ in cookie handling, so a loop that only occurs in a browser points at cookies or `SameSite`. ## Client-side hardening For server-side HTTP clients, set an explicit low redirect cap (3-5 is plenty for an API), log the final effective URL, and treat exceeding the cap as a distinct error class rather than a generic failure. Unbounded following in a service is both a hang risk and, combined with attacker-controlled URLs, an SSRF pivot.
- Why do clients count hops instead of simply failing when a URL repeats in the chain?Because repetition is legitimate: an authentication flow routinely returns to the same application URL after a round trip through an identity provider, now with a session cookie. Aborting on the first repeat would break those flows. Conversely, a malicious or buggy server can emit an unbounded chain of distinct URLs, which URL tracking would never catch. A hop cap bounds both cases.
- You see a loop that only occurs in the browser; curl follows the same URL fine. What does that suggest?Cookie behaviour, since curl without a cookie jar and a browser with one differ sharply. Likely candidates are a session cookie rejected because it is marked Secure over plain http, scoped to the wrong Domain, or blocked by SameSite on a cross-site callback. Inspect the chain for a Set-Cookie that never reappears as a Cookie header on the following request.
saying these in an interview costs you the question
- Claiming HTTP itself limits redirects to some fixed number
- Proposing to abort on any repeated URL, which breaks normal login round trips
- Diagnosing a scheme loop as a DNS or caching problem instead of checking X-Forwarded-Proto
- Leaving a server-side HTTP client following redirects without any cap
- Testing a fix in a browser that has cached a permanent redirect from the broken state