Skip to main content
407

Proxy Authentication Required

Active
RFC 9110 §15.5.8Since 1997Corporate proxies, enterprise networks, forward proxy authentication, CONNECT tunneling

HTTP 407 Proxy Authentication Required indicates the client must first authenticate with an intermediary proxy before the request can be forwarded. Defined in RFC 9110 §15.5.8. The proxy MUST return a Proxy-Authenticate header describing the required authentication scheme.

Description

The 407 Proxy Authentication Required status code is similar to 401 Unauthorized, but it indicates that the client needs to authenticate itself with the proxy rather than the origin server. The proxy MUST send a Proxy-Authenticate header field containing a challenge applicable to the proxy for the requested resource.

This status code exists because HTTP architecture allows intermediary proxies to enforce access control independently of the origin server. The proxy sits between the client and the destination, and before it will relay requests, it demands credentials. The client responds by including a Proxy-Authorization header in subsequent requests — analogous to how Authorization responds to a 401 with WWW-Authenticate.

In practice, 407 is most commonly encountered in corporate and enterprise environments where forward proxies (Squid, Blue Coat, Zscaler, Microsoft ISA/TMG) gate all outbound traffic. Employees' browsers handle proxy auth transparently via system credentials (NTLM, Kerberos, NEGOTIATE), but non-browser HTTP clients — CLI tools, SDKs, CI/CD pipelines, containerized services — frequently break because they lack native proxy authentication support or cannot negotiate complex multi-step auth schemes.

For HTTPS traffic, proxy authentication occurs during the CONNECT tunnel establishment phase. The client sends CONNECT host:443 to the proxy, the proxy responds with 407 before establishing the tunnel, the client retransmits CONNECT with Proxy-Authorization, and only then does the proxy create the TCP tunnel to the origin. This means the proxy never sees the encrypted payload — it only authenticates the tunnel request itself.

The authentication schemes used with 407 range from simple Basic/Digest to enterprise protocols like NTLM (multi-round challenge/response) and Negotiate (SPNEGO wrapping Kerberos). NTLM is particularly problematic because it requires connection persistence across multiple round-trips — breaking connection pooling, load balancers, and stateless HTTP clients that close connections between requests.

Examples

Request through an unauthenticated proxy
http
GET http://api.example.com/data HTTP/1.1
Host: api.example.com
Accept: application/json
User-Agent: CustomApp/2.1
407 response — proxy demands Basic authentication
http
HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: Basic realm="Corporate Proxy"
Content-Type: text/html
Content-Length: 182 Connection: keep-alive

<html><body><h1>407 Proxy Authentication Required</h1><p>This proxy requires authentication. Please provide valid credentials.</p></body></html>
CONNECT tunnel request for HTTPS through proxy
http
CONNECT api.example.com:443 HTTP/1.1
Host: api.example.com:443 User-Agent: curl/8.4.0
407 response during CONNECT — Negotiate (Kerberos/NTLM)
http
HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: Negotiate
Proxy-Authenticate: NTLM
Proxy-Authenticate: Basic realm="CORP-PROXY"
Content-Length: 0
Connection: keep-alive
Retry with Proxy-Authorization (Basic scheme)
http
GET http://api.example.com/data HTTP/1.1
Host: api.example.com
Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==
Accept: application/json
User-Agent: CustomApp/2.1
Successful response after proxy authentication
http
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 45

{"status": "ok", "data": [1, 2, 3]}

Edge Cases

  • NTLM proxy auth requires connection persistence across 3 round-trips (Type1→Type2→Type3). HTTP clients that close connections between requests or use connection pooling with different connections per request will fail silently or loop indefinitely.
  • When a proxy returns both Negotiate and NTLM in Proxy-Authenticate, the client must prefer Negotiate (SPNEGO/Kerberos) if available. Falling back to NTLM when Kerberos tickets are obtainable causes unnecessary security degradation and performance overhead.
  • HTTPS CONNECT tunneling means the proxy authenticates the tunnel establishment, not individual requests inside the tunnel. Once the tunnel is open, subsequent requests flow encrypted end-to-end. Some clients incorrectly send Proxy-Authorization inside the tunnel after establishment.
  • Proxy authentication credentials are per-connection for connection-oriented schemes (NTLM) but per-request for stateless schemes (Basic). Clients that preemptively send Basic Proxy-Authorization on every request avoid the 407 round-trip penalty entirely.
  • Chained proxies (client → proxy A → proxy B → origin) can each independently return 407. The client must authenticate with proxy A, which then independently authenticates with proxy B. The Proxy-Authorization header is hop-by-hop and MUST NOT be forwarded.
  • PAC (Proxy Auto-Configuration) files can route different URLs through different proxies, each requiring different credentials. A single 407 handler is insufficient — clients need per-proxy credential resolution.
  • Some corporate proxies return 407 with an HTML body containing a redirect to a captive portal for credential entry. Non-browser clients receive this as an opaque error because they cannot render or interact with the portal page.

When You'll See This

  • Corporate laptop making API calls through a Squid/Blue Coat forward proxy that requires domain credentials
  • CI/CD pipeline (Jenkins, GitHub Actions self-hosted runner) failing to pull dependencies because the build agent sits behind an authenticating proxy
  • Docker container trying to reach external registries through an enterprise proxy that demands NTLM authentication the container runtime doesn't support
  • curl or wget command failing in a corporate environment until --proxy-user credentials are supplied
  • Python requests library throwing ProxyError because the system's proxy requires Kerberos tickets the process hasn't acquired
  • Node.js application behind a Zscaler proxy receiving 407 on all outbound HTTPS calls because the http.Agent doesn't handle Proxy-Authenticate negotiation
  • Mobile app on corporate WiFi failing API calls because the network's transparent proxy intercepts and demands authentication the app wasn't designed to handle

Implementation References

LanguageConstant
Gohttp.StatusProxyAuthRequired
Rusthttp::StatusCode::PROXY_AUTHENTICATION_REQUIRED
Pythonhttp.HTTPStatus.PROXY_AUTHENTICATION_REQUIRED
Node.jshttp.STATUS_CODES[407]
.NETHttpStatusCode.ProxyAuthenticationRequired
JavaHttpURLConnection.HTTP_PROXY_AUTH
PHPResponse::HTTP_PROXY_AUTHENTICATION_REQUIRED (Symfony)
Ruby:proxy_authentication_required (Rack)

History

Introduced in HTTP/1.1 (RFC 2068, January 1997) alongside the broader proxy architecture. Carried forward unchanged through RFC 2616 (June 1999) and refined in RFC 9110 (June 2022, §15.5.8). The semantics have remained stable — what changed dramatically is the authentication scheme complexity, from Basic/Digest in the 1990s to NTLM/Negotiate/Kerberos in enterprise deployments of the 2000s-2020s.

Related Status Codes

Related Headers

FAQ

What is the difference between 401 Unauthorized and 407 Proxy Authentication Required?

401 means the origin server rejected your credentials (or you didn't send any). The server sends WWW-Authenticate, and you respond with Authorization. 407 means an intermediary proxy — not the final destination — is blocking you. The proxy sends Proxy-Authenticate, and you respond with Proxy-Authorization. They're structurally identical mechanisms applied at different points in the request chain: 401 is end-to-end (client↔origin), 407 is hop-by-hop (client↔proxy).

Why do non-browser HTTP clients struggle with 407 while browsers handle it transparently?

Browsers integrate deeply with the operating system's credential store (Windows SSPI, macOS Keychain, Linux GSSAPI). When they receive a 407 with Negotiate or NTLM, they automatically acquire Kerberos tickets or perform NTLM handshakes using the logged-in user's domain credentials. Non-browser clients (curl, Python requests, Node.js http) lack this OS integration by default. They need explicit configuration: proxy credentials in environment variables (HTTP_PROXY with embedded user:pass), platform-specific auth libraries (pywin32, node-sspi), or helper tools (cntlm, px-proxy) that act as a local unauthenticated proxy and handle NTLM/Kerberos upstream.

How do I handle 407 in automated environments like Docker containers and CI/CD pipelines?

Three common approaches: (1) Configure HTTP_PROXY/HTTPS_PROXY environment variables with embedded credentials (http://user:pass@proxy:port) — works for Basic auth but exposes credentials in environment. (2) Run a local authentication proxy (cntlm, px-proxy) inside the container or on the build agent that handles NTLM/Kerberos negotiation and exposes an unauthenticated local proxy endpoint. (3) Whitelist the build agent's IP at the proxy level so it bypasses authentication entirely. Option 2 is most common for NTLM environments. For Kerberos, you need a keytab file and kinit before the process starts.