407 Proxy Authentication Required: Causes and Fixes

HTTP 407 means the proxy rejected your credentials or got none. The exact causes, fixes for curl, Python, and browsers, and how to verify.

VoidMob Team
9 min read

HTTP 407 Proxy Authentication Required comes from the proxy, not the website you requested. It means the proxy accepted your TCP connection, found no credentials it would accept on the request, and stopped there. Fix it by sending the correct username and password (or authenticating by whitelisted IP), in the format your client expects.

The response carries a Proxy-Authenticate header naming the scheme the proxy wants, most commonly Basic (MDN's 407 reference has the header semantics). Your client answers with Proxy-Authorization. If that header is missing, malformed, stripped, or carries stale credentials, you get 407 again.

What 407 is not

  • It is not a website block. The proxy stopped the request before forwarding it, so the target server normally never sees it.
  • It is not a 403 or a captcha. Those come from the destination and mean your IP or fingerprint was judged. If you are chasing that instead, read Proxy Detected: What It Means and How to Fix It.
  • It is not a bandwidth error, although an exhausted or suspended plan can surface as an auth rejection on some gateways.

The seven causes, in the order worth checking

1. No credentials sent at all

The most common case. You set a proxy host and port but the username and password never made it into the request. In curl the proxy URL must carry them or you pass -U. In a browser or OS-level proxy setting, credentials are prompted separately and are not part of the host field.

2. Wrong port for the credential set

A credential pair is usually valid on one gateway endpoint only. Pasting list-mode credentials into a flex-mode endpoint (or the reverse) authenticates against the wrong table and returns 407. On VoidMob, proxy-list credentials connect on proxy.voidmob.com:10000; flex-gateway credentials, which come from the POST /v1/proxies/:id/flex_credentials endpoint, connect on proxy.voidmob.com:10092. They are not interchangeable.

3. Special characters in the password

@, :, /, # and ? inside a password break URL parsing. http://user:p@ss@host:10000 splits at the first @, so the proxy receives a truncated username. Percent-encode the password, or pass credentials out-of-band (-U in curl, an auth object in Playwright, a dict field in Python).

4. Rotated or regenerated password

Regenerating a list password invalidates the old one immediately. Every worker still holding the old string starts returning 407 the moment it reconnects. Redeploy the credential everywhere, not just in the machine you tested from.

5. Source IP not on the whitelist

If the order authenticates by IP instead of by login, a changed egress IP means rejection. Cloud workers behind an autoscaling NAT, a home connection on a dynamic IP, and a CI runner all qualify. IP-whitelist lists return no username and password at all, so a snippet with credentials in it will also fail.

6. Malformed username parameters

Gateways that read targeting from the username treat a typo as a bad username. Country codes are uppercase (_c_US, not _c_us), prefixes are case-sensitive (_c_, not _C_), and city names replace spaces with hyphens. Also do not mix syntaxes: a proxy list takes geo as a field when you create it, so appending _c_US to a list username changes the username and produces 407.

7. Client or middlebox stripping the header

Some HTTP clients drop Proxy-Authorization after a redirect, and some libraries do not send it on a CONNECT tunnel for HTTPS. Corporate networks that run their own upstream proxy also rewrite the header. Symptom: HTTP works, HTTPS returns 407, or the first request works and a redirect does not.

Fixes by client

ClientCorrect formCommon mistake
curlcurl -x "http://<user>:<pass>@proxy.voidmob.com:10000" https://ipinfo.io/jsonHost set with -x but credentials only in ~/.netrc, which curl does not use for proxies
curl (out-of-band)curl -x http://proxy.voidmob.com:10000 -U "<user>:<pass>" https://ipinfo.io/jsonLeaving a special character unencoded inside -x
Python requestsproxies={"http": "http://<user>:<pass>@proxy.voidmob.com:10000", "https": "http://<user>:<pass>@proxy.voidmob.com:10000"}Setting only the http key, so HTTPS bypasses auth and 407s
Playwrightproxy={"server": "http://proxy.voidmob.com:10000", "username": "<user>", "password": "<pass>"}Putting credentials inside server, which Chromium ignores
Selenium / Chrome flagsExtension or local auth forwarder that supplies Proxy-Authorization--proxy-server with inline credentials; Chrome drops them
apt / OS levelAcquire::http::Proxy "http://<user>:<pass>@host:port";Relying on an env var set for your shell but not for sudo

Full, verified setups for the browser automation cases live in Playwright proxy setup, Puppeteer proxy setup and Selenium proxy setup. The curl flag reference is in curl proxy.

Environment variables are a frequent false lead

http_proxy and https_proxy are read by curl, apt and many libraries, but not all, and browsers generally take their proxy from the OS or their own settings instead. If a request succeeds in your shell and fails in your app, print the effective proxy config inside the app rather than assuming the variable applied.

Isolate it in one command

Run the smallest possible request that only tests authentication:

curl -v -x "http://<list-username>:<list-password>@proxy.voidmob.com:10000" https://ipinfo.io/json

Read the verbose output in this order:

  1. Proxy-Authorization: Basic ... present in the request? If not, your client never built the header. Credential formatting is the problem.
  2. HTTP/1.1 407 with Proxy-Authenticate: Basic? The header was sent and rejected. The credentials, the port, or the whitelist is wrong.
  3. HTTP/1.1 200 Connection established then a JSON body? Auth is fine. Any failure after this belongs to the target site, not the proxy.

A returned JSON body means you are authenticated and exiting from the pool. Confirm the exit is what you expected before you blame anything else.

Confirm your proxy exit IP after authenticating

If the credential works but the IP looks wrong (datacenter instead of mobile, wrong country), that is a targeting issue, not a 407 issue. The Proxy Validator tests both in one pass.

The failure mode most guides miss: 407 that appears only under load

A credential that works in a single curl but 407s in production is usually hitting a per-account concurrency or state limit, not a typo. Three concrete versions:

  • Password rotated mid-run. One worker regenerates, the rest keep the old string. Treat credentials as deployed config, not as something a worker fetches opportunistically.
  • Suspended or exhausted package. A GB package must be active for its lists to authenticate. A drained plan can read as an auth failure rather than a quota message, so check the order state before debugging code.
  • Mixed credential sets in one pool of workers. If half your workers were seeded from a list you later deleted, those 407 permanently while the rest succeed. The tell is a stable failure percentage rather than random errors.

Retry logic should distinguish these. A 407 is not transient: retrying the same request with the same credentials produces the same result and burns your rate budget. Fail the worker loudly, alert, and only retry after a credential refresh.

When to switch auth method instead of debugging

IP whitelisting removes the credential problem entirely and is the better fit when your egress IP is fixed, for example a single VPS or a bastion host. VoidMob lists take up to five IPv4 addresses or /24 to /32 subnets, set at creation time only, and those lists return no username or password at all. Do not choose it for autoscaled workers or a home connection with a dynamic IP: you will trade 407 for a silent block every time your address changes.

1How do I fix error 407 Proxy Authentication Required?

Send valid credentials in the form your client supports, on the port those credentials belong to. Check in this order: credentials present in the request at all, correct port for the credential set, special characters percent-encoded, password not regenerated, source IP whitelisted if the order uses IP auth.

2What does proxy authentication required actually mean?

The proxy received your connection, looked for a Proxy-Authorization header, and did not find a valid one. It answers 407 with a Proxy-Authenticate header naming the scheme it accepts. The destination server was never contacted, so nothing about the target site caused the error.

3Why does curl work but my Python script return 407?

Usually because the script sets only the http key in the proxies dict, so HTTPS requests go out without credentials, or because the password contains a character that breaks URL parsing inside the proxy string. Set both keys, and percent-encode the password.

4Can a 407 mean my plan ran out of data?

It can. A package has to be active for its credentials to authenticate, so an exhausted or suspended order can surface as a rejected login rather than a quota message. Check the order state in the dashboard before rewriting code.

5Should my code retry on 407?

No. A 407 is a configuration answer, not a transient network condition, so the same request with the same credentials will fail identically. Stop the worker, surface the error, and retry only after the credential or whitelist has been changed.

6Does 407 mean the site detected my proxy?

No. Detection happens at the destination and shows up as 403, a captcha, or a soft block. A 407 never reaches the destination.

Credentials that work on the first request

Proxy lists with their own login, geo target and rotation rule, plus IP-whitelist auth when you have a fixed egress.