Axios Proxy Setup in Node.js: HTTP, HTTPS & SOCKS5
Axios has a built-in proxy option, and for years it was the single most common reason "axios proxy not working" got typed into a search box. Here is how the option actually behaves on HTTP vs HTTPS targets, when to switch to https-proxy-agent or socks-proxy-agent, and how to authenticate against a mobile proxy.
Quick Answer
For anything beyond a plain HTTP target, the battle-tested pattern is: set proxy: false and pass an explicit agent, new HttpsProxyAgent(proxyUrl) as httpsAgent for an HTTP proxy, or new SocksProxyAgent(proxyUrl) for SOCKS5. It works on every axios version and it is the only way to use SOCKS at all.
- →The built-in
proxyoption is HTTP-proxy only; there is no SOCKS field in the request config - →Older axios releases mishandled HTTPS targets through HTTP proxies; a cleartext leak was only patched in v1.16.1 (May 2026)
- →
proxy: falsealso disableshttp_proxy/https_proxyenv vars, so the agent is the single source of truth
The examples below use the placeholder credentials from a mobileproxies.org slot: proxy.mobileproxies.org, HTTP port 8000, SOCKS5 port 1080, username u_4a9c, password p_2X7q. Swap in your own values from the dashboard. Everything here applies to any HTTP or SOCKS5 proxy, but the sticky and rotating patterns at the end assume a carrier-grade mobile IP, the kind used for web scraping behind consumer-grade trust. Versions used: axios 1.18.x, https-proxy-agent 9.1.0, socks-proxy-agent 10.1.0.
The built-in proxy option
Axios accepts a proxy object on any request or instance. Per the request config docs it defines the hostname, port, and protocol of the proxy server, and the nested auth object sends HTTP Basic credentials to the proxy. Axios also honors the conventional http_proxy and https_proxy environment variables, with no_proxy as a comma-separated exclusion list.
const axios = require("axios")
const client = axios.create({
proxy: {
protocol: "http", // set "https" only if the proxy itself speaks TLS
host: "proxy.mobileproxies.org",
port: 8000,
auth: {
username: "u_4a9c",
password: "p_2X7q",
},
},
})
// Forward-proxy mode: the request goes to the proxy with a
// Proxy-Authorization header stamped on it
const res = await client.get("http://example.com/")For http:// targets this is simple forward proxying and it works fine. The docs note that protocol refers to the proxy server itself: if your proxy endpoint is plain HTTP (most are, including mobile proxy gateways), keep it http even when the target URL is HTTPS. Setting proxy: false disables proxying entirely and ignores the environment variables, which matters in the next section.
Why HTTPS targets break it
An HTTPS request through an HTTP proxy is supposed to use the CONNECT method: the client asks the proxy to open a raw TCP tunnel to the origin, then negotiates TLS end-to-end inside that tunnel. The proxy never sees the URL path, headers, or body. Axios's built-in proxy handling historically did not get this right, which is why community answers for "axios https proxy" have long recommended a workaround rather than the official option.
The project's own changelog documents how recently this was still being fixed:
v1.16.1 (May 13, 2026) - security fix
"Proxy Cleartext Leak: Fixed an issue where HTTPS request data could be transmitted in cleartext to an HTTP proxy under certain configurations." In other words, request data destined for a TLS origin could reach the proxy unencrypted.
v1.17.0 (June 1, 2026) - tunneling fix
"Preserved user httpsAgent TLS options when tunneling HTTPS requests through HTTP CONNECT proxies." Custom ca, cert, and rejectUnauthorized settings were previously dropped when a tunnel was built.
Current v1.x docs
As of axios 1.18, the docs state that for https:// targets axios establishes a CONNECT tunnel and performs TLS end-to-end with the origin, sending Proxy-Authorization on the CONNECT request only.
So on a fully up-to-date axios, the built-in option now tunnels HTTPS correctly. But any project pinned below 1.16.1 is exposed to the cleartext behavior, and plenty of production lockfiles are. The agent-based setup below sidesteps the whole history: it behaves identically on every axios version because axios simply hands the socket work to your agent. The docs are explicit that if you supply an HttpsProxyAgent, axios leaves tunneling to that agent.
The fix: https-proxy-agent
https-proxy-agent is an http.Agent implementation that connects to your HTTP proxy and issues the CONNECT method itself. Pass it as httpsAgent (axios uses httpAgent for http targets and httpsAgent for https targets), and set proxy: false so axios's own proxy logic and any HTTP_PROXY env vars stay out of the way.
npm install axios https-proxy-agent http-proxy-agent
const axios = require("axios")
const { HttpsProxyAgent } = require("https-proxy-agent")
const { HttpProxyAgent } = require("http-proxy-agent")
// Credentials go in the proxy URL itself
const proxyUrl = "http://u_4a9c:p_2X7q@proxy.mobileproxies.org:8000"
const client = axios.create({
proxy: false, // hand all proxying to the agents
httpAgent: new HttpProxyAgent(proxyUrl), // for http:// targets
httpsAgent: new HttpsProxyAgent(proxyUrl), // CONNECT tunnel for https://
})
const { data } = await client.get("https://api.ipify.org?format=json")
console.log(data.ip) // carrier IP, not your machine's addressThe constructor is new HttpsProxyAgent(proxy, options?) where proxy is a URL string or URL object, and options accepts the usual http.Agent constructor options such as keepAlive. Because the agent speaks CONNECT, it also carries WebSockets and anything else that tunnels over proxies. If you need the same wiring in Go instead of Node, the pattern maps directly onto http.Transport, covered in our mobile proxy for Go guide.
SOCKS5 with socks-proxy-agent
Axios's request config has no SOCKS support at all, so socks-proxy-agent is not a workaround here, it is the only route. Same pattern: one agent, both slots, proxy: false.
const axios = require("axios")
const { SocksProxyAgent } = require("socks-proxy-agent")
// socks5h = SOCKS v5 with DNS resolved on the proxy (no local DNS leak)
const agent = new SocksProxyAgent(
"socks5h://u_4a9c:p_2X7q@proxy.mobileproxies.org:1080"
)
const client = axios.create({
proxy: false,
httpAgent: agent,
httpsAgent: agent,
})
const res = await client.get("https://example.com/")The URL scheme picks the SOCKS version and where DNS happens. From the package source: socks5h and plain socks resolve hostnames on the proxy side, socks5 resolves them locally before connecting, and socks4 / socks4a select the legacy v4 protocol. If no port is given it defaults to 1080. Prefer socks5h with a mobile proxy so DNS answers come from inside the carrier network rather than your local resolver.
Not sure whether you should be on SOCKS5 or plain HTTP CONNECT in the first place? The practical differences, and when they matter, are in SOCKS5 vs HTTP proxy.
Proxy authentication, both syntaxes
There are two places credentials can live, and mixing them up is the usual cause of 407 Proxy Authentication Required:
Built-in proxy option
proxy.auth takes { username, password }. Per the docs this sets a Proxy-Authorization header and overwrites any Proxy-Authorization you set manually via headers. Do not confuse it with the top-level auth config, which authenticates against the target site, not the proxy.
Agent-based setup
Credentials are embedded in the proxy URL: http://user:pass@host:port or socks5h://user:pass@host:1080. Both agent packages read them from the URL; socks-proxy-agent percent-decodes them before use.
Because URL credentials are parsed as part of a URL, special characters must be percent-encoded, an @ in a password will otherwise split the URL at the wrong place:
const user = encodeURIComponent("u_4a9c")
const pass = encodeURIComponent("p@ss:w0rd") // "@" -> %40, ":" -> %3A
const proxyUrl =
"http://" + user + ":" + pass + "@proxy.mobileproxies.org:8000"Sticky vs rotating usage patterns
With a mobile proxy the interesting decision is not the transport, it is how long you keep the same carrier IP. A sticky session keeps one IP for the life of a logged-in session or a multi-step flow; a rotating pattern requests a fresh IP between batches. The trade-offs are covered in rotating vs static mobile proxies; here is what each looks like in axios.
For sticky work, create one axios instance per identity and enable keepAlive on the agent so TCP connections are reused across requests:
const session = axios.create({
proxy: false,
httpsAgent: new HttpsProxyAgent(proxyUrl, { keepAlive: true }),
})For rotation, mobileproxies.org exposes a switch endpoint: one authenticated POST forces the modem onto a new carrier IP, and your existing axios client keeps working through the same proxy hostname:
// Goes direct (no proxy), authenticated with your API key
await axios.post(
"https://buy.mobileproxies.org/api/v1/proxies/us-mob-01/switch",
null,
{ headers: { Authorization: "Bearer " + process.env.MP_API_KEY } }
)
// Give the modem a few seconds to bind the new IP, then verify
await new Promise((r) => setTimeout(r, 4000))
const { data } = await client.get("https://api.ipify.org?format=json")
console.log("new egress IP:", data.ip)One caution: the rotation call itself must not go through the proxy client. Use the default axios export or a separate instance for control-plane calls, and your proxied client for the actual traffic.
Common failures
407 Proxy Authentication Required
Credentials missing or in the wrong place. Built-in option: proxy.auth, not top-level auth. Agents: credentials in the URL, percent-encoded.
Requests bypass the proxy or double-proxy
A stray HTTP_PROXY / HTTPS_PROXY env var is being picked up alongside your config. Set proxy: false whenever you pass agents; per the docs it disables proxies and ignores the environment variables.
Works for http://, fails for https://
The signature of the CONNECT problem on an older axios. Upgrade to 1.17+ or, more robustly, move to the httpsAgent: new HttpsProxyAgent(proxyUrl) pattern.
DNS resolves locally on SOCKS
You used socks5://. Switch the scheme to socks5h:// so hostname resolution happens on the proxy side.
Sources
- • Axios docs - Request Config (proxy, httpAgent/httpsAgent, env vars)
- • Axios README (v1.x) - proxy behavior for http vs https targets, CONNECT tunneling, Proxy-Authorization
- • Axios CHANGELOG - v1.16.1 proxy cleartext leak fix, v1.17.0 CONNECT tunneling TLS options fix
- • Axios releases - v1.18.1 current as of June 2026
- • https-proxy-agent README - constructor API, CONNECT method behavior
- • http-proxy-agent README - agent for http:// targets
- • socks-proxy-agent README and source - URL schemes, versions, DNS behavior, URL credentials
Related Guides
Point axios at a real carrier IP
Dedicated 4G/5G mobile proxies with HTTP and SOCKS5 endpoints, credential auth, and an API for on-demand rotation. Drop the hostname into the configs above and go.