Originally published on proxymint.

A 407 means the proxy, not the site, rejected or never got your login. Causes in the order to check, and the fix for curl, Python, Node, browsers and apt.

TL;DR

  • A 407 comes from the proxy, not the website. The proxy got no credentials or the wrong ones, answered with a Proxy-Authenticate challenge, and never forwarded the request to the site.
  • The challenge scheme tells you which problem you have. Basic means a provider or simple proxy that wants a username and password. NTLM or Negotiate means a corporate proxy that wants a Windows or domain login.
  • On HTTPS the 407 answers the CONNECT, so there is no response object. Clients raise errors such as "Tunnel connection failed: 407" or "CONNECT tunnel failed, response 407", and credentials must ride on the CONNECT itself.
  • Most 407s are placement or encoding. Credentials in a field the client ignores, a requests proxies dict without an https key, or an unencoded @, : or % in the password cause most cases.

Key takeaways

  • Run curl -v through the proxy with and without -U first. If -U works, fix how the client sends credentials; if it fails, fix the credentials or the account.
  • Percent-encode the username and password in code. Use urllib.parse.quote with safe set to empty, or encodeURIComponent, because a % followed by two hex digits silently changes the password.
  • Use each client's own credential fields. Playwright needs username and password fields, Puppeteer needs page.authenticate, and Java needs jdk.http.auth.tunneling.disabledSchemes cleared.
  • Never retry a 407 in a loop. Treat it as a configuration error, alert, and keep retries for 429 and 5xx responses.

Read the full guide on proxymint, with the commands, tables and sources.