What a captive portal does
RFC 8952, the IETF’s captive portal architecture, uses the term for a network that a device joins voluntarily but where network access is limited until some requirements are met. The user typically has to open a web browser to meet them: read an advertisement, accept an acceptable-use policy, or provide credentials. Apple’s developer guidance names the familiar settings: Wi-Fi on an aeroplane, in a cafe, or at a hotel.
To do this, a captive portal needs a web server for the portal page, a way to allow or block each device’s traffic, and a way to tell the user they need to sign in. Once the conditions are met, the network lifts the block. Some sessions are limited by time or data, after which the device is captive again.
How devices detect them today
Before newer standards, captive portals relied on intercepting traffic, and they still can. RFC 8952 describes current solutions as forging DNS or HTTP responses, and some as attempting man-in-the-middle proxying of HTTPS, so that a request for any site returns the portal page instead.
Operating systems work around this by probing. Apple’s guidance says iOS and macOS send a probe when they first join a network to detect interception, and then show the portal login page. Android exposes the results to apps through NetworkCapabilities. NET_CAPABILITY_CAPTIVE_PORTAL indicates the network was found to have a captive portal the last time it was probed. NET_CAPABILITY_INTERNET means the network is configured to reach the internet, which it may or may not actually do, and NET_CAPABILITY_VALIDATED means the system found real internet connectivity the last time it checked. Android’s reference advises apps that care about actual connectivity to look at both.
The standard approach
The IETF published a set of documents in 2020 to replace guessing with an explicit signal.
- RFC 8910 defines a Captive-Portal option for DHCPv4 (option 114), DHCPv6 (option 103) and IPv6 Router Advertisements (option 37). The option carries the URI of the portal’s API. A network without a portal can send a reserved value,
urn:ietf:params:capport:unrestricted, so devices can skip time-consuming detection. - RFC 8908 defines that API. The device fetches JSON with the media type
application/captive+json. The one required key,captive, says whether the device is held. Optional keys includeuser-portal-urlfor the sign-in page, which must be served over TLS,venue-info-url,seconds-remaining,bytes-remainingandcan-extend-session. - RFC 8952 sets out the architecture and its requirements, among them that solutions must not require forging DNS or HTTP responses and should let clients avoid TLS interception without a person clicking through a warning.
Apple’s guidance, published in June 2020, describes support for these DHCP and RA options and the JSON API in iOS 14 and macOS Big Sur, and requires the API server to run with TLS.
Why captive portals confuse apps
To an app, a captive network looks like a working connection that fails in odd ways. The device reports Wi-Fi as connected. Requests to the app’s servers time out, return the portal’s page instead of the expected response, or fail certificate validation because HTTPS traffic was intercepted. RFC 8952 notes that portals that work by altering DNS or HTTP generally only function as intended with browsers, breaking other applications, and that applications using other protocols are not alerted at all.
Apple’s guidance describes a second case: when a session expires mid-use, interception can make Safari and other apps load the wrong page or show a security warning. A user who was online moments ago is suddenly captive again.
Designing for captive networks
- Check validated connectivity, not link state. A Wi-Fi connection is not the same as reaching your server. Use the platform’s validated and captive portal signals before deciding the network is usable.
- Do not treat a portal as a server outage. Keep the user’s work on the device and send it when the network is usable, as described in what happens to a write made offline.
- Never accept an intercepted response. Keep certificate validation strict. A portal page served in place of your API is not your API.
- Tell the user what is needed. “Sign in to this Wi-Fi network” is more useful than “Something went wrong”.
- Keep local features working. A captive network only blocks traffic routed through it. Features that use a direct device-to-device link, or data already on the device, can carry on, which is the idea behind graceful degradation.