Fixing "407 Proxy Authentication Required"

A 407 means the proxy rejected your credentials before the request left. Work through the seven causes, from quoting bugs to whitelist conflicts.

A 407 Proxy Authentication Required comes from the proxy, not the website. Your request stopped at our edge because the credentials attached to it were missing, malformed, or not valid for the endpoint you sent them to. Every cause is local to your machine or your account, and each has a check you can run in a minute.

First, reproduce it outside your application

Strip the problem to a single command before changing any code:

curl -v -x http://USERNAME:PASSWORD@HOST:PORT https://api.ipify.org

Keep the -v flag: curl prints the Proxy-Authorization header it actually sent, which is often not the one you thought you were sending.

Cause 1: the endpoint belongs to a product your account does not hold

Symptom: the credential is correct and works on one host but not another.

Your account has one proxy credential, and it works on every product the account holds an active plan for. Sent to a gateway you hold no plan for, it is refused with a 407 that looks exactly like a wrong password. The usual cases: a free account pointed at the rotating or residential gateway (the free tier is static shared datacenter, HTTP only), or a plan that has lapsed.

Check: open Plans and confirm an active plan for the product whose host you are connecting to. Then copy the host and port from that product's row on the Proxies page rather than from an older config. Authentication covers which credential goes where.

Cause 2: special characters in the password

Symptom: the password contains @, :, /, # or %, and curl -v shows a username or host you did not intend.

In a proxy URL those characters have structural meaning. A password of p@ss:word in http://user:p@ss:word@host:port is parsed as username user, password p, and hostname ss:word@host.

Fix: percent-encode the password (@ becomes %40, : becomes %3A, / becomes %2F, # becomes %23, % becomes %25):

# password is  p@ss:word
curl -x http://USERNAME:p%40ss%3Aword@HOST:PORT https://api.ipify.org

Or pass the credentials separately, which curl accepts verbatim:

curl -x http://HOST:PORT -U 'USERNAME:p@ss:word' https://api.ipify.org

In code, use the language's URL-encoding function (encodeURIComponent in JavaScript, urllib.parse.quote in Python) rather than encoding by hand, which is how a % in an already-encoded password gets encoded twice.

Cause 3: invisible characters from copy and paste

Symptom: the credential looks right in an editor and still fails.

A value copied from a web page, chat client or PDF can carry a trailing newline, a non-breaking space, a zero-width character or a curly quote. None of them are visible; all of them change the password.

Check:

# Reveal exactly what is in the variable, including characters that do not print
printf '%q\n' "$PROXY_PASSWORD"

Anything beyond the characters you expect (\r, \n, a stray space) is the cause. Retype the value by hand once to confirm, then fix whatever introduced it. .env files preserve a trailing space after the value in most parsers.

Cause 4: the whitelist and your source address disagree

Symptom: a setup with no username configured worked for days and now fails, often after a reboot, an outage or overnight.

Node4 has two authentication modes, and they are alternatives rather than layers. With IP whitelisting, available on every product, you register your public address and connect with no credentials (on residential, a whitelisted connection carries no username and so gets an untargeted exit). If your source address has changed (a new office, a rebuilt container, a reassigned VPS, a home line that rotated overnight), requests now arrive from an address the whitelist has never seen, there are no credentials to fall back on, and the proxy answers 407.

Check: find your current address from the machine that carries the traffic, then compare it with Auth & IP Access in the dashboard:

curl -s https://api.ipify.org

A free account may whitelist 1 address; paid plans include 3. If your address changes often, username and password authentication is the more stable choice. IP whitelisting best practices covers the environments where the whitelist holds up.

Cause 5: a targeting segment typo on a gateway product

Symptom: the bare credential works, but a username with -country- or -session- segments fails.

Residential and rotating gateway products carry targeting in the username, as in USERNAME-country-us, and a malformed segment makes the whole username unrecognizable. The rules that bite most often:

A location with no available exits is refused rather than silently redirected, so you see an error instead of data from the wrong country.

Check: drop every segment and connect with the bare username. If that works, the problem is in the segments; country and city targeting has the full grammar.

Cause 6: the library is not sending the credentials you configured

Symptom: curl works, your application gets 407.

Python requests applies credentials from the proxy URL correctly, but proxies set on a session after a connection has been pooled do not apply retroactively. Configure them before the first request:

import requests

proxies = {
    "http":  "http://USERNAME:PASSWORD@HOST:PORT",
    "https": "http://USERNAME:PASSWORD@HOST:PORT",
}
r = requests.get("https://api.ipify.org", proxies=proxies, timeout=30)
print(r.text)

The https entry uses an http:// scheme. That is correct: it describes how to reach the proxy, not how the proxy reaches the target.

Node's fetch and axios do not read proxy settings from a URL the way curl does, and axios's proxy option has changed behavior across major versions. An explicit proxy agent is more predictable; Node.js proxy setup covers the current approach.

Headless browsers: Chromium accepts a proxy server on the command line but not credentials, and instead fires an authentication event the script has to answer. A script that never answers it gets a 407 on every navigation. Puppeteer and Playwright covers both.

Cause 7: the account cannot authenticate right now

Symptom: everything above checks out and the credential still fails everywhere.

Checklist

  1. Reproduce with curl. If curl works, the bug is in the application.
  2. Confirm the account holds an active plan for the host you are calling.
  3. Percent-encode the password, or pass it with -U.
  4. Check for invisible characters with printf '%q'.
  5. If using the whitelist, compare your current public address with the entries.
  6. Strip targeting segments back to the bare username.
  7. Check the account is verified, in credit and inside its allowance.

If the error persists after all seven, open a ticket from the dashboard with the verbose curl output (password redacted) and the exact host and port. That output usually identifies the cause at once.

Not yet on a plan? The free tier provisions 3 free shared proxies with 1 GB/month bandwidth and 10 concurrent threads, enough to confirm a credential and a target work together.