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:
- The client connects to the proxy and sends a request. For an HTTPS site that is
CONNECT example.com:443. - If it carries no valid credentials, the proxy answers
407 Proxy Authentication Requiredwith aProxy-Authenticate: Basicheader naming the scheme it wants. - 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 runs | Is the public IP fixed? | How to make it fixed |
|---|---|---|
| Cloud VM with a public IP | Usually, if you reserve it (Elastic IP, static external IP) | Reserve the address rather than using an ephemeral one |
| Private subnets, containers, Kubernetes | The NAT's IP is what the proxy sees | Route egress through a NAT gateway with a reserved IP |
| Office network | Often, on a business line | Ask your ISP for a static IP |
| Home broadband | Usually not; it changes on reconnect | Update the allowlist when it changes, or use credentials |
| GitHub-hosted CI runners | No | GitHub recommends larger runners with static IPs or self-hosted runners |
| Serverless functions | No, unless routed through a NAT | Route 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 password | IP allowlist | |
|---|---|---|
| Works from | Anywhere | Only listed public IPs |
| Secrets in code or config | Yes | None |
| Chrome and Selenium with Chrome | Awkward: credentials in --proxy-server are ignored | Works: nothing to send |
| SOCKS5 in Chromium browsers and Playwright | Not possible: they cannot send SOCKS5 credentials | Works |
| Laptops, home networks, CI | Works | Breaks when the IP changes |
| Leak risk | A leaked password works from anywhere | A leaked host and port are useless from other IPs |
| Main failure mode | 407 from a typo or unencoded character | 407 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:PORTjust 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:
- Username and password. Copy the details in whichever format your tool expects:
HOST:PORT:USER:PASS,HOST:PORT@USER:PASS,USER:PASS:HOST:PORTorUSER:PASS@HOST:PORT. In code, buildhttp://USERNAME:PASSWORD@HOST:PORTfrom environment variables. - IP allowlist. Switch the order to IP allowlist authentication and add the public IP your traffic leaves from. Then connect to
HOST:PORTwith 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:
- Keep them out of code. Read
PROXY_URLorPROXY_USERNAMEandPROXY_PASSWORDfrom the environment or a secret manager. Never commit them. - Keep them out of logs.
curl -vprints theProxy-Authorizationheader, and the base64 in it decodes to your password. Redact verbose output before you paste it anywhere, including support tickets. - 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.
- 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.
- Rotate when people or machines leave. Change credentials when a teammate leaves or a server is retired, and remove its address from any allowlist.
- 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.
- 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.