Proxy authentication is how a proxy decides whether to serve a connection. There are two common methods: username and password, sent by your client in a Proxy-Authorization header, and an IP allowlist (often called IP whitelisting), where the proxy accepts any connection from a public IP address you have listed. Credentials work from anywhere; an allowlist needs a fixed IP but no secrets in your code. On ProxyHive, both are available per order.

Which one to pick depends less on security than on where your code runs. The rest of this page shows what goes over the wire for each, when the allowlist is the only practical option, and how to keep either one from leaking.

How proxy authentication works: 407 and Proxy-Authorization

Username and password proxy authentication is HTTP's Basic scheme, defined in RFC 7617, with proxy-specific headers from RFC 9110. The exchange has three steps:

  1. The client connects to the proxy and sends a request. For an HTTPS site that is CONNECT example.com:443.
  2. If it carries no valid credentials, the proxy answers 407 Proxy Authentication Required with a Proxy-Authenticate: Basic header naming the scheme it wants.
  3. The client repeats the request with Proxy-Authorization: Basic <base64 of username:password>, and the proxy opens the tunnel.

Most clients skip step 2 when the credentials are in the proxy URL and send them on the first request. This is exactly what curl sent to a local test proxy, captured with nc listening on the port:

CONNECT api.ipify.org:443 HTTP/1.1
Host: api.ipify.org:443
Proxy-Authorization: Basic YWxpY2U6czNjcmV0LXBhc3M=
User-Agent: curl/8.5.0
Proxy-Connection: Keep-Alive

And here is that header decoded:

echo YWxpY2U6czNjcmV0LXBhc3M= | base64 -d
alice:s3cret-pass

Base64 is an encoding, not encryption. Anyone who sees that line has the password.

Credentials in the proxy URL

The usual way to pass credentials is inside the proxy URL: http://USERNAME:PASSWORD@HOST:PORT. Characters such as @, :, / and # in a password break that URL unless you percent-encode them:

from urllib.parse import quote

proxy = f"http://{quote(USERNAME, safe='')}:{quote(PASSWORD, safe='')}@{HOST}:{PORT}"

A password of p@ss:w/rd#1 becomes p%40ss%3Aw%2Frd%231. Unencoded, it is the most common cause of a 407 with the right password. Our proxy error codes guide has the rest of the 407 checklist.

Is the proxy password sent in clear text?

It depends on which leg you mean.

Between you and the proxy: yes, for http:// and socks5:// proxy URLs. An http:// proxy URL means the connection to the proxy is plain TCP, so the Proxy-Authorization line above crosses the network readable. RFC 7617 is blunt: Basic "is not a secure method of user authentication". SOCKS5 is no better: its username and password method, RFC 1929, carries the password in cleartext too.

Between the proxy and the website: no. Proxy-Authorization is meant for the proxy only; RFC 9110 says it "applies only to the next inbound proxy that demanded authentication". For HTTPS sites the credentials sit in the CONNECT request, which never leaves the proxy. We checked the plain-HTTP case as well: a request to http://httpbin.org/headers through our authenticating test proxy came back without any Proxy-Authorization header, because the proxy removed it before forwarding.

Your traffic to the website is still encrypted. The TLS session for an HTTPS site runs inside the tunnel, end to end. Only the proxy credentials travel in the clear.

So the real question is who can watch the path between your machine and the proxy. On a server in a cloud region, few parties can. On café Wi-Fi, more can. Some clients can also encrypt the hop to the proxy itself with an https:// proxy URL, where a provider supports it. For ProxyHive orders, use the HTTP port with an http:// proxy URL, and prefer the allowlist on networks you do not trust.

IP allowlist (IP whitelisting) explained

With an IP allowlist, the proxy looks at the source address of the incoming connection and serves it if the address is on the order's list. No header, no password, nothing in your code. The proxy URL shrinks to http://HOST:PORT.

That makes the allowlist depend entirely on one fact: the public IP your traffic leaves from must be fixed and known. Find it by asking an echo service without the proxy:

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

The -4 matters. If your machine prefers IPv6, the address you look up and the address you connect from may differ. Compare the result with what you put on the allowlist.

Where a fixed egress IP comes from:

Where the code runsIs the public IP fixed?How to make it fixed
Cloud VM with a public IPUsually, if you reserve it (Elastic IP, static external IP)Reserve the address rather than using an ephemeral one
Private subnets, containers, KubernetesThe NAT's IP is what the proxy seesRoute egress through a NAT gateway with a reserved IP
Office networkOften, on a business lineAsk your ISP for a static IP
Home broadbandUsually not; it changes on reconnectUpdate the allowlist when it changes, or use credentials
GitHub-hosted CI runnersNoGitHub recommends larger runners with static IPs or self-hosted runners
Serverless functionsNo, unless routed through a NATRoute through a NAT with a reserved IP, or use credentials

One trap on home and mobile connections is carrier-grade NAT, where many customers share one public IPv4 address. Allowlisting that address lets everyone behind it use your proxy. If curl -4 https://api.ipify.org returns an address you share with your whole neighbourhood, use a username and password instead.

IP allowlist vs username and password

Username and passwordIP allowlist
Works fromAnywhereOnly listed public IPs
Secrets in code or configYesNone
Chrome and Selenium with ChromeAwkward: credentials in --proxy-server are ignoredWorks: nothing to send
SOCKS5 in Chromium browsers and PlaywrightNot possible: they cannot send SOCKS5 credentialsWorks
Laptops, home networks, CIWorksBreaks when the IP changes
Leak riskA leaked password works from anywhereA leaked host and port are useless from other IPs
Main failure mode407 from a typo or unencoded character407 after your IP changes

When the IP allowlist wins

Choose the allowlist when the client makes credentials hard or impossible:

  • Chrome, Edge and Selenium with Chrome. Chrome ignores a username and password in --proxy-server, and WebDriver cannot type into the browser's sign-in prompt. Our Selenium proxy guide walks through the options; the allowlist is the one with no code.
  • SOCKS5 from a Chromium browser. Chromium cannot authenticate to a SOCKS5 proxy at all, and Playwright rejects SOCKS5 with a username or password. With an allowlist, socks5://HOST:PORT just connects. Our comparison of HTTP vs SOCKS5 proxies covers the protocol side.
  • Apps and OS proxy settings that neither store credentials nor prompt for them.
  • Fixed servers. A scraper on a VM with a reserved IP never needs a secret in its environment.

When username and password wins

Choose credentials when the network moves:

  • Laptops and home connections, where the IP changes without warning.
  • CI and serverless, unless you route egress through a fixed NAT address.
  • Many machines on many networks, where keeping a list current is more work than handing out a secret.
  • Shared or CGNAT addresses, where allowlisting would admit strangers.

Setting it up on a ProxyHive order

Every order in the dashboard at https://app.proxyhive.io lists its host, port, username and password, and each ISP or datacenter IP is its own endpoint. Authentication is chosen on the order:

  1. Username and password. Copy the details in whichever format your tool expects: HOST:PORT:USER:PASS, HOST:PORT@USER:PASS, USER:PASS:HOST:PORT or USER:PASS@HOST:PORT. In code, build http://USERNAME:PASSWORD@HOST:PORT from environment variables.
  2. IP allowlist. Switch the order to IP allowlist authentication and add the public IP your traffic leaves from. Then connect to HOST:PORT with no credentials.

Test either with one command before you point a real job at it:

curl -x "http://USERNAME:PASSWORD@HOST:PORT" "https://api.ipify.org?format=json"
curl -x "http://HOST:PORT" "https://api.ipify.org?format=json"

The first is for credentials, the second for the allowlist. Both should print the proxy's IP, not yours. Static IPs pair naturally with allowlists on the other side too: a partner API that allowlists your egress needs an address that never changes, which is what a static ISP proxy gives you from a single IP.

Rotating credentials and security hygiene

Treat proxy credentials like any API key:

  1. Keep them out of code. Read PROXY_URL or PROXY_USERNAME and PROXY_PASSWORD from the environment or a secret manager. Never commit them.
  2. Keep them out of logs. curl -v prints the Proxy-Authorization header, and the base64 in it decodes to your password. Redact verbose output before you paste it anywhere, including support tickets.
  3. Keep them out of shell history. A password typed into a command line is saved. Use environment variables, or a leading space if your shell ignores those lines.
  4. Separate jobs. On residential proxies you can create sub-users, each with its own credentials and share of traffic, so one leaked credential or runaway job does not expose the rest.
  5. Rotate when people or machines leave. Change credentials when a teammate leaves or a server is retired, and remove its address from any allowlist.
  6. Prune the allowlist. An old entry for a VM whose IP went back to the cloud provider's pool is an entry someone else may now own.
  7. Act fast on a leak. If a password shows up where it should not, contact support straight away, and in the meantime watch the order's usage for traffic you did not send.

Pick the method your client and network make easy, lock it down, and test it with a single curl before anything else depends on it.