Understanding HTTP 511 Network Authentication Required: The Captive Portal Code
511 Network Authentication Required is a status code almost no application developer will ever write code to return — and that's by design. It exists for one specific job: letting a network (not your server) tell a client "you need to log in to this Wi-Fi, not to whatever you were actually trying to reach." This post covers what 511 promises, why the RFC explicitly forbids origin servers from generating it, and why it's a different animal from 401 even though both are about missing credentials.
What Is a 511?
A 511 tells a client that network-level authentication — not application-level authentication — is standing between it and the internet.
The 511 status code indicates that the client needs to authenticate to gain network access. — RFC 6585, Section 6
In plain English: you're not being denied by the website you're trying to reach — you're being intercepted by the network itself (airport Wi-Fi, a hotel gateway, a coffee shop's router) before your request ever gets there, and that network wants you to log in, accept terms, or pay first.
Don't reach for 511 when what you actually mean is "this user isn't logged into my application." That's 401 or 403. 511 is specifically for the network layer intercepting traffic before it reaches its destination — most application developers will never write code that returns it.
Who's Allowed to Send a 511
This is the detail that makes 511 different from almost every other status code in the spec: the RFC doesn't just describe what the code means, it restricts who's allowed to generate it.
The 511 status SHOULD NOT be generated by origin servers; it is intended for use by intercepting proxies that are interposed as a means of controlling access to the network. — RFC 6585, Section 6
That's a deliberate, load-bearing restriction. Your application server — the thing running your Express or Next.js code — has no business ever emitting a 511. It's meant for the network gear sitting in front of every destination: the router or gateway in a coffee shop, hotel, or airport that's silently intercepting outbound requests and answering on behalf of whatever site the client was actually trying to reach.
The Captive Portal Story
The RFC's own example is the clearest explanation of why this code exists at all. A network operator wants to require login (or accept-terms, or payment) before granting internet access. It does this by identifying unauthenticated clients — historically by MAC address — and blocking all of their traffic except requests to a dedicated "login server":
GET /index.htm HTTP/1.1
Host: www.example.comThe client thinks it's asking www.example.com for a page. It's actually talking to the network's login server, which intercepts the request and answers with a 511:
HTTP/1.1 511 Network Authentication Required
Content-Type: text/html
<html>
<head>
<title>Network Authentication Required</title>
<meta http-equiv="refresh"
content="0; url=https://login.example.net/">
</head>
<body>
<p>You need to <a href="https://login.example.net/">
authenticate with the local network</a> in order to gain
access.</p>
</body>
</html>The RFC also specifies what the response shouldn't contain: "the 511 response SHOULD NOT contain a challenge or the login interface itself, because browsers would show the login interface as being associated with the originally requested URL, which may cause confusion." In other words, don't put the actual login form inline in the 511 body — redirect the user to the login server's own page instead, as the example above does with the meta refresh, so the address bar clearly shows the user is on the network's login page, not on www.example.com.
Why This Isn't Just 401
401 and 511 both mean "you need to authenticate before I'll give you what you asked for" — but the two relationships they describe are completely different:
- 401 is between the client and the destination application — the origin server itself is saying "log into me."
- 511 is between the client and the network it's connected to — some intermediary between the client and the destination is saying "log into me before you can even reach the destination."
The distinction matters practically, not just semantically. Software that speaks HTTP but isn't a browser — an API client, a background sync job, an IoT device — has no way to distinguish "the destination server wants credentials" from "the network silently swapped in a login page" unless the status code tells it. A 401 from api.example.com means retry with credentials against api.example.com. A response claiming to be from api.example.com that's actually a captive portal page would, without 511, look exactly like a broken or hijacked API response — the client can't tell it's not really talking to the API at all. 511 exists specifically to make that distinguishable, which is also why the RFC prohibits caching it: Responses with the 511 status code MUST NOT be stored by a cache.
511 vs 401 vs 407
| Code | Who's asking for credentials | Relationship | Standard? |
|---|---|---|---|
| 401 Unauthorized | The destination application | Client ↔ origin server | Yes (RFC 9110) |
| 407 Proxy Authentication Required | A proxy the client explicitly configured | Client ↔ known, configured proxy | Yes (RFC 9110) |
| 511 Network Authentication Required | An intercepting network gateway | Client ↔ network the client didn't choose to authenticate with | Yes (RFC 6585) |
407 and 511 can look similar — both involve an intermediary rather than the final destination — but 407 is for a proxy the client knowingly configured (and expects to authenticate with), while 511 is for a network silently intercepting traffic the client believed was going straight through.
Why Application Developers Rarely Touch This
Because the RFC scopes 511 to intercepting proxies and network gateways, there's no meaningful "Returning 511 Correctly" section for Express or Next.js route handlers the way there is for 401 or 403 — writing that code in your application server would be misusing the status code. If you're building the login-server side of an actual captive portal (embedded router firmware, a hotel Wi-Fi gateway), the shape of the response is exactly the RFC's example above: a 511 status, Content-Type: text/html, and a redirect to a separate login page rather than an inline form.
What you're more likely to build instead is a client that handles 511 gracefully — an API client or mobile app that, on receiving one, recognizes it isn't a real API error and surfaces "you need to sign in to this Wi-Fi network" instead of treating it as a failed request to your own backend.
Common Pitfalls
- Returning 511 from application code to mean "please log in." That's 401. 511 is reserved for network-layer interception, not your app telling a user their session expired.
- Putting the actual login form in the 511 response body. The RFC explicitly recommends against this — redirect to a separate login page so the browser's address bar doesn't misleadingly associate the login UI with the original destination.
- Caching a 511 response. The spec prohibits it outright, and for good reason: a cached captive-portal page served up after the client actually authenticates would incorrectly block access to a site that's now reachable.
- Building API clients that don't handle 511 as a distinct case. If your client treats every non-2xx response as "the API failed," a captive portal response will look like a cryptic API error instead of what it actually is — surfacing it distinctly ("connect to this Wi-Fi network first") is a better user experience than a generic error toast.
Wrapping Up
511 exists to solve a narrow but real problem: letting non-browser clients tell the difference between "the destination rejected me" and "the network I'm on hijacked my request." The rules of thumb:
- 511 means the network wants you to authenticate, not the destination server
- The RFC says origin servers SHOULD NOT generate it — it's for intercepting proxies and gateways only
- It's distinct from 401 (destination auth) and 407 (a proxy you chose to use)
- Never cache a 511 response, and never embed the login form directly in it — redirect instead
For more, see our pages on 511 Network Authentication Required, 401 Unauthorized, and 407 Proxy Authentication Required, or our 401 Unauthorized post for the destination-side half of this story.