Axios Proxy Setup: HTTP, HTTPS, Agents, and 407 Errors
Configure an authenticated proxy in Axios 1.18, understand HTTP versus HTTPS routing, separate agents from proxy selection, and diagnose 407, 403, timeout, and credential-log failures.
Axios
HTTP client library
Axios request
Node HTTP adapter
Route selector
proxy object | environment
Bypass or agent
NO_PROXY | proxy:false
Hop evidence
absolute-form | CONNECT | 407
Keep explicit proxy config, environment discovery, bypass rules, and agent policy as separate controls so every failure remains attributable to one hop.
Operating principle
Keep explicit proxy config, environment discovery, bypass rules, and agent policy as separate controls so every failure remains attributable to one hop.
Start With an Explicit Axios Proxy Object
For a Node.js service that owns its routing policy, an explicit Axios instance is the least ambiguous starting point. Keep the destination URL, proxy endpoint, and proxy credentials in separate fields. The proxy protocol describes the client-to-gateway connection; an https:// destination can travel through an http proxy because Axios creates a CONNECT tunnel for the destination TLS session.
import axios from 'axios';
const client = axios.create({
adapter: 'http',
proxy: {
protocol: 'http',
host: process.env.DATABAY_PROXY_HOST,
port: Number(process.env.DATABAY_PROXY_PORT),
auth: {
username: process.env.DATABAY_PROXY_USER,
password: process.env.DATABAY_PROXY_PASS,
},
},
timeout: 10_000,
maxRedirects: 3,
maxContentLength: 10 * 1024 * 1024,
maxBodyLength: 1 * 1024 * 1024,
transitional: { clarifyTimeoutError: true },
redact: ['password', 'authorization', 'proxy-authorization'],
});
const response = await client.get(
'https://databay.com/what-is-my-ip/json',
);
console.log(response.data);This guide and its capture apply to Axios's Node HTTP adapter, not browser JavaScript. A browser cannot open an arbitrary forward-proxy socket through Axios request config; browser traffic is governed by the browser or operating-system proxy configuration and by origin security policy. Pin and review your Axios version. The observations below were reproduced on Axios 1.18.1 and Node 24.14.0, not assumed from older snippets.
What the Local Axios Lab Actually Observed
We ran isolated listeners on 127.0.0.1 on 2026-07-27. No public proxy or public destination was contacted. The HTTPS case used the reserved name example.test and stopped immediately after the proxy response, before destination TLS. Synthetic passwords were reduced to their length in the evidence.
| Case | Proxy evidence | Result |
|---|---|---|
| HTTP destination, explicit proxy and auth | GET http://127.0.0.1:PORT/path | The proxy received Basic credentials; the forwarded destination did not receive Proxy-Authorization. |
| HTTPS destination, explicit HTTP proxy | CONNECT example.test:443 | Credentials appeared on CONNECT and the lab stopped before destination TLS. |
HTTP_PROXY | One absolute-form request | Axios discovered the proxy from the environment. |
Exact host-and-port NO_PROXY | No proxy connection | The destination was reached directly. |
proxy: false | No proxy connection | The environment proxy was disabled for that request. |
Custom keep-alive http.Agent | Two requests on one client-to-proxy socket | The agent controlled connection reuse; it did not define the proxy address. |
| Proxy 407 | Proxy request only | Axios rejected with status 407 before the destination was reached. |
| Destination 403 | Authenticated proxy request plus destination request | Axios rejected with status 403 after forwarding. |
| Stalled proxy | TCP connection, no HTTP response | A 150 ms configured timeout rejected with ETIMEDOUT. |
The sanitized Axios observation ledger preserves the full machine-readable record. It is a protocol and failure-boundary artifact, not a latency benchmark and not evidence about public proxy quality.
HTTP Targets and HTTPS Targets Use Different Proxy Messages
For an HTTP destination, the proxy needs the complete destination URL, so Axios 1.18.1 sent an absolute-form request target:
GET http://service.example/report?id=42 HTTP/1.1
Host: service.example
Proxy-Authorization: Basic <redacted>For an HTTPS destination through the same HTTP proxy, Axios asked the proxy to open a byte tunnel:
CONNECT service.example:443 HTTP/1.1
Host: service.example:443
Proxy-Authorization: Basic <redacted>After a successful CONNECT response, destination TLS belongs inside that tunnel. The proxy protocol and destination protocol answer different questions: proxy.protocol: 'http' does not downgrade an https:// destination. Axios 1.18.1's official request-config documentation explicitly describes this CONNECT behavior and confines Proxy-Authorization to the CONNECT request. The current release line also includes a defense-in-depth fix first shipped in 1.16.1 for a cleartext leak in some HTTPS-through-HTTP-proxy configurations, which is a concrete reason not to copy an unpinned old workaround.
If the proxy itself requires TLS, set its protocol to https and configure the proxy trust boundary deliberately. Do not set rejectUnauthorized: false as a catch-all repair; first identify whether certificate validation failed on the proxy hop or the destination hop.
Choose One Routing Control and Record Its Precedence
Axios supports both explicit configuration and conventional environment variables. Mixing them without an ownership rule makes the route difficult to audit.
| Control | Best fit | Observed or documented boundary |
|---|---|---|
config.proxy | One instance or request with application-owned routing | The explicit local proxy won even when HTTP_PROXY pointed at a different listener. |
HTTP_PROXY | HTTP destinations in a controlled worker environment | The Axios HTTP adapter discovered it when no explicit proxy was supplied. |
HTTPS_PROXY | HTTPS destinations in a controlled worker environment | The variable name describes the destination scheme; its value can describe an HTTP gateway. |
NO_PROXY | Approved destinations that must use a direct route | An exact 127.0.0.1:PORT match bypassed the lab proxy. |
proxy: false | Disable Axios proxy discovery or let a custom proxy agent own routing | The request went direct even while HTTP_PROXY was present. |
Axios also documents a newer boundary: when the selected Node agent has native proxyEnv enabled, Axios defers environment-proxy handling to Node. That branch was not enabled in our Windows lab, so treat it as an official-documentation boundary and test it on your exact Node startup flags and agents. Log only a route class such as explicit, environment, bypass, or agent; never log a credential-bearing environment value.
An Agent Is a Socket Policy, Not Automatically a Proxy
Axios exposes httpAgent and httpsAgent so Node applications can control connection pooling, socket limits, TLS material, and other transport behavior. A plain http.Agent does not contain a proxy address. In the lab, a plain agent plus proxy: false connected directly. With explicit proxy config, a keep-alive agent reused one client-to-proxy socket for two sequential requests.
import http from 'node:http';
import axios from 'axios';
const proxySocketPool = new http.Agent({
keepAlive: true,
maxSockets: 20,
maxFreeSockets: 5,
});
const client = axios.create({
adapter: 'http',
proxy: {
protocol: 'http',
host: process.env.DATABAY_PROXY_HOST,
port: Number(process.env.DATABAY_PROXY_PORT),
auth: {
username: process.env.DATABAY_PROXY_USER,
password: process.env.DATABAY_PROXY_PASS,
},
},
httpAgent: proxySocketPool,
timeout: 10_000,
});
// Destroy a process-owned custom agent during graceful shutdown.
process.once('beforeExit', () => proxySocketPool.destroy());Do not add a custom agent merely because an old article says modern Node lacks keep-alive. Add one when you need explicit socket limits, TLS options, instrumentation, or a third-party proxy implementation. If a custom proxy agent owns routing, follow that agent's version-pinned contract and normally set proxy: false so Axios does not apply a second proxy layer. This lab did not test SOCKS agents; use the HTTP versus SOCKS5 decision guide before selecting a different protocol.
Keep Credentials Out of URLs, Logs, and Error Objects
The explicit proxy.auth object avoids URL-encoding mistakes when a password contains @, :, /, or %. Axios converted the lab's reserved-character password into the expected Basic proxy credential. The destination never received that header.
The less obvious leak surface is error logging. An AxiosError carries the request config, which can contain proxy authentication. Axios 1.18 supports a redact list for error.toJSON(). Our lab set redact: ['password'], triggered a 407 with an intentionally wrong secret, and confirmed the serialized password became [REDACTED ****].
const safeErrorClient = axios.create({
// ...proxy and timeout config...
redact: [
'password',
'authorization',
'proxy-authorization',
'cookie',
'set-cookie',
],
});
try {
await safeErrorClient.get('https://service.example/health');
} catch (error) {
if (!axios.isAxiosError(error)) throw error;
const safe = error.toJSON();
console.error({
name: safe.name,
code: safe.code,
status: error.response?.status ?? null,
message: safe.message,
});
}Redaction changes serialized output; it does not erase the original request config, the process environment, or request headers. Do not dump error.config, a proxy URL, request headers, or environment variables. Retrieve production values from a secret manager, restrict their scope, and rotate them after unintended exposure.
Distinguish Proxy 407 From Destination 401, 403, and 429
The Axios error code alone does not identify the responsible hop. In the lab, both the proxy 407 and destination 403 used ERR_BAD_REQUEST. The status and path evidence made them different.
| Evidence | Owner of the decision | Next safe check |
|---|---|---|
error.response.status === 407 | Forward proxy authentication | Verify the proxy credential field, account status, documented username grammar, and authentication scheme. The lab destination was never reached. |
| CONNECT returns 4xx or 5xx | Proxy tunnel policy or upstream path | Preserve the proxy response and test one approved destination. Do not weaken destination TLS. |
error.response.status === 401 | Destination authentication | Check the destination token or session. Proxy credentials cannot satisfy it. |
error.response.status === 403 | Usually the destination after a request is forwarded | Stop and verify permission, official API availability, and source policy. Do not rotate identity to evade the decision. |
error.response.status === 429 | Destination or intermediary rate control | Honor Retry-After, reduce rate, and use an authorized quota. |
error.code === 'ECONNREFUSED' | TCP connection target | Check the configured proxy host, port, listener, and egress firewall. |
error.code === 'ETIMEDOUT' | Configured time budget expired | Determine whether the stall occurred before a proxy response or after forwarding; do not call it a 407. |
A response proves a component answered, not that the route is safe or authorized. The proxy request-path guide maps TCP, proxy authentication, CONNECT, destination TLS, and destination HTTP into separate evidence layers.
Bound Time, Response Size, Redirects, and Retries
Axios documents no finite default timeout, and response/body size limits can be unlimited unless configured. A production request to a destination you do not fully control needs explicit budgets. The lab used a deliberately stalled proxy and confirmed that timeout: 150 with clarifyTimeoutError: true rejected as ETIMEDOUT without reaching the destination.
const client = axios.create({
timeout: 10_000,
maxRedirects: 3,
maxContentLength: 10 * 1024 * 1024,
maxBodyLength: 1 * 1024 * 1024,
transitional: { clarifyTimeoutError: true },
});
const controller = new AbortController();
const overallBudget = setTimeout(() => controller.abort(), 15_000);
try {
const response = await client.get('https://service.example/report', {
signal: controller.signal,
});
// Consume only the fields the job needs.
console.log(response.status);
} finally {
clearTimeout(overallBudget);
}A timeout and an AbortSignal answer related but different operational needs: the Axios timeout bounds request inactivity/elapsed request behavior in the adapter, while a caller-owned signal can enforce a workflow-level cancellation. Test both in your runtime. Automatic retries should be bounded and limited to authorized, idempotent work whose failure semantics are understood. Never retry or rotate automatically after 401, 403, 407, CAPTCHA, quota, or an unclear authorization boundary.
Use a Hop-Aware Axios Error Classifier
Classify only what the error proves. Avoid string matching on the full message, and do not include secret-bearing request config in logs.
import axios from 'axios';
export function classifyAxiosFailure(error) {
if (!axios.isAxiosError(error)) {
return { layer: 'application', retryable: false };
}
const status = error.response?.status;
if (status === 407) {
return { layer: 'proxy-auth', status, retryable: false };
}
if (status === 401 || status === 403) {
return { layer: 'destination-access', status, retryable: false };
}
if (status === 429) {
return { layer: 'destination-rate', status, retryable: false };
}
if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') {
return { layer: 'time-budget', status: null, retryable: 'policy' };
}
if (error.code === 'ECONNREFUSED') {
return { layer: 'tcp-connect', status: null, retryable: false };
}
if (error.request && !error.response) {
return { layer: 'no-http-response', status: null, retryable: 'investigate' };
}
return { layer: 'http-response', status: status ?? null, retryable: false };
}retryable: 'policy' is intentionally not a Boolean approval. The caller still needs to know the method, whether a body may have been processed, the remaining time budget, and the source's access policy. Preserve a privacy-safe route class, attempt count, Axios version, status, and error code. Do not record the proxy username, hostname, complete destination URL, headers, response body, or cookies.
Add Databay Pool, Country, and Session Controls Last
First prove the base Axios control path against an endpoint you own. Then add one documented Databay routing control at a time to the proxy username so any failure has one new variable:
# Base route
DATABAY_PROXY_USER='USER-zone-residential'
# Request a US exit estimate
DATABAY_PROXY_USER='USER-zone-residential-countryCode-us'
# Request short-lived continuity for an authorized workflow
DATABAY_PROXY_USER='USER-zone-residential-countryCode-us-sessionId-axios-qa-01'Set DATABAY_PROXY_HOST=gw.databay.co and DATABAY_PROXY_PORT=8888, then pass the username and password through proxy.auth. A country control requests a pool selection; it does not reproduce language, cookies, account settings, GPS, device state, or every localization input. A session control requests route continuity; it is not a user identity or dedicated device.
Choose datacenter proxies for an approved workload that values infrastructure throughput, or residential proxies when the test genuinely requires a consumer-network route or country sample. Use the destination's official API, export, preview, or testing environment first when it satisfies the job.
Reproduce the Evidence Before Shipping
The repository harness is designed to fail when Axios behavior drifts. From the frontend project directory, run:
npm run content:verify-axiosThe command starts only localhost listeners, runs the asserted cases, prints the observation ledger, and refreshes public/data/axios-proxy-lab-2026-07-27.json. Review the diff instead of accepting a changed snapshot automatically. Record the operating system, Node version, Axios version, adapter, and test date with any approval.
The public ledger is safe to download because it contains synthetic credentials reduced to a username and password length, sanitized ephemeral ports, and no public traffic. It does not validate Databay production availability, external certificate chains, SOCKS behavior, browser Axios, redirects across real origins, or application-specific retry safety. Those boundaries need separate tests when they matter.
Production Release Checklist
- Pin and record the approved Node and Axios versions.
- Choose one route owner: explicit proxy config, environment policy, or a reviewed custom proxy agent.
- Keep proxy endpoint and credential fields separate; retrieve secrets at runtime.
- Set a finite timeout, response-size limit, request-body limit, and redirect limit.
- Add explicit
AxiosError.toJSON()redaction and log only a safe error envelope. - Verify HTTP absolute-form and HTTPS CONNECT behavior against a controlled endpoint.
- Prove that
NO_PROXYandproxy: falseselect the intended direct route. - Classify 407 at the proxy separately from 401, 403, and 429 at the destination.
- Bound retries to authorized idempotent operations; stop at access and quota decisions.
- Destroy process-owned custom agents during graceful shutdown.
- Re-run the localhost harness after a Node, Axios, agent, or proxy-policy change.
- Verify the observed exit without treating one 200 response as proof of anonymity or future availability.
This approved guide is maintained by Robert Smith and independently reviewed by James Johnson. Re-run the evidence workflow after material Node, Axios, agent, or proxy-policy changes.
Questions specific to Axios
Does Axios support HTTP and HTTPS destinations through an HTTP proxy?
Why does my Axios proxy return 407?
What is the difference between proxy 407 and destination 403 in Axios?
Does httpAgent configure the Axios proxy?
How do I disable HTTP_PROXY for one Axios request?
Can I hide an Axios proxy password with the redact option?
Should I disable TLS verification when an Axios proxy fails?
Does this Axios setup work in the browser?
When is an Axios proxy timeout safe to retry?
Same gateway, different control surface
Python Requests
HTTP client library
Session -> HTTPAdapter policy -> proxy hop -> approved destination
Choose the exit pool after the control path works. Use residential for reputation-sensitive targets or datacenter for throughput.
Ship Axios to production
Create an account, drop in your gateway credentials, and route your first Axios request in minutes.
Pricing, order minimums, and traffic validity vary by product.