Authenticating Curl Through a Proxy: Commands That Work

The command that works, the libcurl equivalent, what --proxy-anyauth is for, and what to try when the proxy refuses Basic authentication.

Need the working command right now? Here it is: curl -x http://proxy:8080 -U user:pass https://example.com. That single line handles curl proxy authentication for most HTTP and HTTPS proxies. If the proxy doesn't accept Basic auth outright and needs to negotiate, add --proxy-anyauth and let curl figure out the scheme. If you already know the scheme, skip the guesswork and force it with --proxy-basic, --proxy-ntlm, --proxy-digest, or --proxy-negotiate.

For libcurl, the C API equivalent takes three calls: set CURLOPT_PROXY to your proxy URL, set CURLOPT_PROXYUSERPWD to "user:pass", and optionally set CURLOPT_PROXYAUTH to CURLAUTH_ANY or a specific bitmask like CURLAUTH_NTLM.

Pro Tip: -U authenticates you to the proxy. -u authenticates you to the destination server. Mixing them up produces a 407 that looks identical to a bad password.

Key Takeaways

Curl proxy authentication comes down to matching the right flag (-U, --proxy-anyauth, or a forced scheme) to what the proxy actually supports, and never leaving credentials exposed in plain text.

PointDetails
Use -U, not -u-U sends credentials to the proxy; -u sends them to the destination server, and mixing them causes silent 407 failures.
Force schemes when knownSkip --proxy-anyauth's extra round-trip by using --proxy-ntlm or --proxy-digest once you know the proxy's scheme.
Encode special charactersPercent-encode colons and at-signs in embedded proxy credentials so curl doesn't misparse the URL.
Diagnose with -vcurl -v reveals the Proxy-Authenticate header on a 407, telling you exactly which scheme to force.

Table of Contents

Curl Proxy Authentication Command Examples for Common Scenarios

Every proxy auth scenario in curl boils down to combining -x (set the proxy) with a credential flag. Here are the patterns you'll actually use.

  1. Basic auth over HTTP proxy. curl -x http://proxy.example.com:8080 -U myuser:mypass https://api.example.com. This is the default: curl tries Basic first unless told otherwise.
  2. Avoid exposing the password in your shell history. Run curl -x http://proxy.example.com:8080 -U myuser https://api.example.com and curl prompts for the password interactively, keeping it out of ps output and shell logs.
  3. Force a specific scheme. If you already know the proxy expects NTLM, skip negotiation entirely: curl -x http://proxy.example.com:8080 --proxy-ntlm -U 'DOMAIN\user:pass' https://api.example.com. Swap in --proxy-digest or --proxy-basic as needed.
  4. Let curl negotiate. curl -x http://proxy.example.com:8080 --proxy-anyauth -U user:pass https://api.example.com asks the proxy which schemes it supports before committing. It works reliably, but it costs an extra round-trip compared to specifying the scheme upfront, which matters if you're firing thousands of requests through a scraping pipeline.
  5. SOCKS5 proxy. curl --socks5 proxy.example.com:1080 -U user:pass https://example.com or equivalently curl -x socks5://user:pass@proxy.example.com:1080 https://example.com.

On the security note: credentials passed via -U or embedded in a -x URL are visible to anyone who can read your shell history or process list on a shared machine. Prefer the interactive prompt, a .netrc file, or an environment variable set in a script that isn't logged.

Most of these commands eventually have to move out of a terminal and into application code, and that translation is where the proxy argument is most often dropped or mistranslated between libraries. The curl converter takes a working command and emits the equivalent Python, Node.js, PHP or Go, proxy flags included, which is a faster route to a correct first request than rewriting the invocation from memory. It sits alongside the rest of the free developer tools.

Setting Proxy Authentication in Libcurl (C API)

If you're building the request in C rather than shelling out to the curl binary, the mapping from CLI flags to curl_easy_setopt calls is direct. You set three options and you're done.

Setting CURLOPT_PROXYAUTH to CURLAUTH_ANY tell libcurl which HTTP proxy authentication methods to allow, and lets curl query the proxy to pick one it supports. That flexibility isn't free: it triggers an extra request/response cycle before the real transfer starts, the same latency cost you see with --proxy-anyauth on the command line.

A minimal pattern looks like this:

curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy.example.com:8080");
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "myuser:mypass");
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY);

libcurl copies the string you pass to CURLOPT_PROXYUSERPWD internally, so you don't need to keep the buffer alive after the call, and calling the option again simply overwrites the previous value.

HTTP vs SOCKS Proxies and Which Auth Scheme to Use

Not every proxy speaks the same protocol, and not every scheme fits every situation. Here's how curl handles the split.

Environment Variables and Encoding Rules You Need to Know

curl reads http_proxy, https_proxy, and ALL_PROXY automatically, and it honors NO_PROXY to bypass the proxy entirely for listed hosts. ALL_PROXY acts as a catch-all when protocol-specific variables aren't set, but an explicit https_proxy always wins over it for HTTPS traffic.

Pro Tip: Store proxy credentials in a .netrc file with 600 permissions, or pull them from an environment variable set at runtime. Both keep secrets out of your shell history and out of curl -v transcripts you might paste into a support ticket.

How to Fix a 407 Proxy Authentication Required Error

A 407 means the proxy rejected your credentials or received none at all. Work through this in order.

  1. Run curl -v against the target. The verbose output shows the exact Proxy-Authenticate header the proxy sent back, telling you which schemes it supports before you waste time guessing.
  2. Force the reported scheme. If the header says NTLM but you used default Basic auth, add --proxy-ntlm and retry.
  3. Double-check the proxy URL itself. A missing socks5:// prefix, wrong port, or typo in the hostname produces failures that look like auth problems but aren't.
  4. Check NO_PROXY if you expected bypass behavior. A host that should skip the proxy but doesn't (or vice versa) usually traces back to a mismatched NO_PROXY pattern.
  5. Test with known-good credentials on a trivial request first. curl -v -x http://proxy:8080 -U user:pass https://example.com isolates whether the problem is your credentials, your encoding, or the proxy configuration itself.

If step one shows no Proxy-Authenticate header at all, the proxy isn't asking for auth. Something else is wrong, likely a network or firewall issue rather than curl.

What Most Curl Proxy Guides Get Wrong

Most tutorials treat --proxy-anyauth as the safe default, and for a one-off request, it is. But teams running curl at any real volume, thousands of scrapes an hour, a CI pipeline hitting an internal proxy on every build, pay for that convenience in latency. Every negotiated request costs an extra round-trip, and at scale that adds up to real time lost to a handshake you could have skipped by just knowing your proxy's scheme in advance.

The bigger gap is credential handling. A setup can get the -U and -x flags right and still paste the password into a shell script that lands in a git repo. The mechanics of curl proxy authentication are genuinely simple. The discipline around where those credentials live is where most setups actually fail. Prioritize that first: pick one credential storage method (.netrc, a secrets manager, environment injection at runtime) and standardize it across your team before you worry about which auth scheme shaves off milliseconds.

If your infrastructure is stable, force the scheme every time. Reserve --proxy-anyauth for exploratory work against a proxy you don't control yet.

Curl Against Node4 Proxies

Node4's HTTP listeners take Basic authentication, so the plain -U user:pass form is the whole answer and --proxy-anyauth only adds a round-trip. The SOCKS5 listeners take the RFC 1929 username and password. One credential works on every product the account holds, and a paid account can create up to 5 credential sets under Auth & IP Access, so a team can give each pipeline its own instead of sharing one password file.

The alternative is IP whitelisting, which works on every product: register the source address and drop -U entirely. That suits a fixed server; a laptop or CI runner whose address changes should keep credentials. A whitelisted residential connection is untargeted, because country and session segments ride in the username. Dedicated datacenter proxies and residential proxies both work with every command on this page, and plans are on the pricing page.

Sources

Recommended

Related reading

same credentials outside curl, including header and IP-whitelist auth.

start when a command that looks right still fails.