Setting up proxy authentication is where most first-timers get stuck. There are two methods - IP Whitelist and Username:Password - and each has tradeoffs that aren't obvious until you've been burned by the wrong choice. This guide covers both, with working code examples and the security practices your future self will thank you for.
The Two Auth Methods
Proxy providers authenticate connections in one of two ways: they either check the IP address of the machine making the request (IP Whitelist), or they validate a username and password embedded in the proxy URL (Username:Password). Some providers support both.
Method 1: IP Whitelist
IP whitelisting tells the proxy server: "Only accept connections from these specific IP addresses." No credentials are needed in the request - if your IP is on the allowlist, you're in.
Pros:
- No credentials in your code - nothing to leak in a git commit
- Cleaner proxy URLs (no user:pass@ required)
- Works great for server deployments with static IPs
- One less thing to rotate when credentials expire
Cons:
- Breaks immediately when your IP changes (home ISP, dynamic corporate IP, coffee shop)
- Doesn't work for distributed scraping across multiple machines without managing a whitelist
- CI/CD pipelines often get new IPs per build - whitelisting becomes a maintenance nightmare
- If someone else gets your whitelisted IP (ISP reassignment), they get free proxy access
IP Whitelisting on ZentisLabs:
ZentisLabs proxies authenticate with username:password; IP whitelisting is not available. The snippet below shows what a whitelisted connection looks like at providers that offer it. With ZentisLabs, use Method 2.
import requests
# At a provider with IP whitelisting: NO credentials needed# (not available on ZentisLabs; use Username:Password)proxies = { "http": "http://proxy.example.com:PORT", "https": "http://proxy.example.com:PORT",}
r = requests.get("https://httpbin.org/ip", proxies=proxies)print(r.json()) # Works because your server IP is whitelistedMethod 2: Username:Password
Username:Password auth embeds credentials directly in the proxy URL. The proxy server validates these on every connection.
Pros:
- Works from any IP - laptops, cloud functions, CI/CD, distributed workers
- Easy to revoke: rotate the password and all old credentials stop working
- No IP management overhead
Cons:
- Credentials in proxy URL = easy to accidentally log or leak
- URL-encoded format confuses some HTTP libraries with special characters
- Requires credential management at scale (rotation, storage)
Where to Find Your Credentials on ZentisLabs:
- Dashboard → Residential → Generate Proxies (or Mobile / Datacenter; the ISP Proxies page lists your static IPs)
- Copy a generated line:
host:port:username:password - Each proxy type and residential plan has its own username and password
Code Examples
Python - Username:Password
import requestsimport os
# Method 2: Username:Password (load from env NEVER hardcode)PROXY_USER = os.environ["ZentisLabs_USER"] # e.g. "user_abc123"PROXY_PASS = os.environ["ZentisLabs_PASS"] # e.g. "p4ssw0rd"
proxies_auth = { "http": f"http://{PROXY_USER}:{PROXY_PASS}@basic.resi.zentislabs.com:12321", "https": f"http://{PROXY_USER}:{PROXY_PASS}@basic.resi.zentislabs.com:12321",}
# Testr2 = requests.get("https://httpbin.org/ip", proxies=proxies_auth)
print("Auth IP:", r2.json()["origin"])Node.js - Username:Password
const axios = require('axios');const { HttpsProxyAgent } = require('https-proxy-agent');
// Method 2: Username:Password (load from env)const user = process.env.ZentisLabs_USER;const pass = process.env.ZentisLabs_PASS;const authAgent = new HttpsProxyAgent(`http://${user}:${pass}@basic.resi.zentislabs.com:12321`);
// Use in axiosasync function fetchWithAuth() { const { data } = await axios.get('https://httpbin.org/ip', { httpsAgent: authAgent, proxy: false, }); return data.origin;}
// Run it (Node's built-in fetch ignores an agent option, so use axios)(async () => { console.log('IP:', await fetchWithAuth());})();Security Best Practices
Never hardcode credentials. A credential in source code WILL eventually end up in git history, a log file, or a stack trace. It's a matter of when, not if.
- Environment variables: Store credentials in
.envfiles (gitignored) and load withpython-dotenvordotenv - Secrets managers: For production, use AWS Secrets Manager, HashiCorp Vault, or Doppler
- Monitor usage: Check your bandwidth in the ZentisLabs dashboard and turn on the Low Bandwidth Alert email in Settings → Notifications
# .env file (add to .gitignore!)ZentisLabs_USER=user_abc123ZentisLabs_PASS=your_password_here
# Load in shellexport $(cat .env | xargs)
# Verifyecho $ZentisLabs_USERTroubleshooting Auth Errors
| Error | Cause | Fix |
|---|---|---|
| 407 Proxy Auth Required | Wrong or missing credentials | Verify user:pass, check for typos |
| Connection Refused | Wrong port or gateway URL | Check gateway URL in dashboard |
| Timeout | Firewall blocking proxy port | Allow outbound traffic to the port in your proxy line |
| Special chars in password | URL encoding issues | URL-encode: @ = %40, : = %3A |
ZentisLabs uses Username:Password auth, which works from any IP, including dynamic home and office connections.