Route ownership runbook

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

T-09
T-09 / Route ownershipSelect the route before tuning the socketserver-rendered route map

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.

By Robert SmithReviewed by James Johnson18 min runbook

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.

CaseProxy evidenceResult
HTTP destination, explicit proxy and authGET http://127.0.0.1:PORT/pathThe proxy received Basic credentials; the forwarded destination did not receive Proxy-Authorization.
HTTPS destination, explicit HTTP proxyCONNECT example.test:443Credentials appeared on CONNECT and the lab stopped before destination TLS.
HTTP_PROXYOne absolute-form requestAxios discovered the proxy from the environment.
Exact host-and-port NO_PROXYNo proxy connectionThe destination was reached directly.
proxy: falseNo proxy connectionThe environment proxy was disabled for that request.
Custom keep-alive http.AgentTwo requests on one client-to-proxy socketThe agent controlled connection reuse; it did not define the proxy address.
Proxy 407Proxy request onlyAxios rejected with status 407 before the destination was reached.
Destination 403Authenticated proxy request plus destination requestAxios rejected with status 403 after forwarding.
Stalled proxyTCP connection, no HTTP responseA 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.

ControlBest fitObserved or documented boundary
config.proxyOne instance or request with application-owned routingThe explicit local proxy won even when HTTP_PROXY pointed at a different listener.
HTTP_PROXYHTTP destinations in a controlled worker environmentThe Axios HTTP adapter discovered it when no explicit proxy was supplied.
HTTPS_PROXYHTTPS destinations in a controlled worker environmentThe variable name describes the destination scheme; its value can describe an HTTP gateway.
NO_PROXYApproved destinations that must use a direct routeAn exact 127.0.0.1:PORT match bypassed the lab proxy.
proxy: falseDisable Axios proxy discovery or let a custom proxy agent own routingThe 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.

EvidenceOwner of the decisionNext safe check
error.response.status === 407Forward proxy authenticationVerify the proxy credential field, account status, documented username grammar, and authentication scheme. The lab destination was never reached.
CONNECT returns 4xx or 5xxProxy tunnel policy or upstream pathPreserve the proxy response and test one approved destination. Do not weaken destination TLS.
error.response.status === 401Destination authenticationCheck the destination token or session. Proxy credentials cannot satisfy it.
error.response.status === 403Usually the destination after a request is forwardedStop and verify permission, official API availability, and source policy. Do not rotate identity to evade the decision.
error.response.status === 429Destination or intermediary rate controlHonor Retry-After, reduce rate, and use an authorized quota.
error.code === 'ECONNREFUSED'TCP connection targetCheck the configured proxy host, port, listener, and egress firewall.
error.code === 'ETIMEDOUT'Configured time budget expiredDetermine 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-axios

The 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

  1. Pin and record the approved Node and Axios versions.
  2. Choose one route owner: explicit proxy config, environment policy, or a reviewed custom proxy agent.
  3. Keep proxy endpoint and credential fields separate; retrieve secrets at runtime.
  4. Set a finite timeout, response-size limit, request-body limit, and redirect limit.
  5. Add explicit AxiosError.toJSON() redaction and log only a safe error envelope.
  6. Verify HTTP absolute-form and HTTPS CONNECT behavior against a controlled endpoint.
  7. Prove that NO_PROXY and proxy: false select the intended direct route.
  8. Classify 407 at the proxy separately from 401, 403, and 429 at the destination.
  9. Bound retries to authorized idempotent operations; stop at access and quota decisions.
  10. Destroy process-owned custom agents during graceful shutdown.
  11. Re-run the localhost harness after a Node, Axios, agent, or proxy-policy change.
  12. 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.

Troubleshooting desk

Questions specific to Axios

Does Axios support HTTP and HTTPS destinations through an HTTP proxy?
Yes in the tested Node HTTP adapter. Axios 1.18.1 sent an absolute-form request for an HTTP destination and CONNECT for an HTTPS destination. The proxy protocol describes the gateway connection; destination TLS remains inside the CONNECT tunnel after a successful response.
Why does my Axios proxy return 407?
A 407 is a proxy authentication response, not destination authentication. Check proxy.auth, the account and username grammar, and the advertised proxy authentication scheme. Do not move the credential into destination auth or rotate an exit to evade the response.
What is the difference between proxy 407 and destination 403 in Axios?
Both were Axios ERR_BAD_REQUEST responses in the local lab, so inspect error.response.status and hop evidence. The 407 stopped at the proxy and never reached the destination; the 403 appeared only after the authenticated proxy forwarded the request.
Does httpAgent configure the Axios proxy?
A plain Node http.Agent controls socket behavior such as pooling and limits; it does not contain a proxy address. Use Axios proxy config or environment discovery for routing. If a specialized proxy agent owns routing, follow its versioned contract and disable Axios proxy resolution with proxy: false when required.
How do I disable HTTP_PROXY for one Axios request?
Set proxy: false on that request or instance. In the Axios 1.18.1 localhost capture, this bypassed an inherited HTTP_PROXY value and connected directly. Verify the behavior in your Node and agent configuration, especially if native Node proxyEnv support is enabled.
Can I hide an Axios proxy password with the redact option?
The redact list masks matching keys when AxiosError.toJSON() serializes the request config. It does not erase the original config, environment, or headers. Avoid logging error.config and explicitly include password, authorization, proxy-authorization, cookie, and other secret-bearing keys appropriate to the application.
Should I disable TLS verification when an Axios proxy fails?
No. First determine whether the failure belongs to the TLS connection to an HTTPS proxy or the destination TLS session inside CONNECT. Disabling verification hides trust errors and can expose traffic to interception. Configure a scoped, reviewed CA only for a controlled private trust boundary.
Does this Axios setup work in the browser?
No. The proxy object, httpAgent, httpsAgent, and conventional proxy environment behavior described here apply to Node.js. Browser Axios uses browser transports and cannot open an arbitrary forward-proxy connection through request config.
When is an Axios proxy timeout safe to retry?
Only when the operation is authorized and idempotent, the application knows whether a request body could have been processed, and a bounded retry policy has budget remaining. Do not retry or rotate automatically after 401, 403, 407, CAPTCHA, quota, or unclear permission.
Adjacent runbooks

Same gateway, different control surface

  • cURL

    Command-line client

    curl -> proxy auth -> CONNECT or SOCKS -> approved destination

  • Node.js fetch

    HTTP client library

    fetch -> env opt-in or same-package dispatcher -> proxy evidence

  • Python Requests

    HTTP client library

    Session -> HTTPAdapter policy -> proxy hop -> approved destination

  • Incogniton

    Multi-profile browser

    Profile editor -> Databay gateway -> pinned residential exit

  • Playwright

    Browser automation

    Browser process -> isolated contexts -> independent exit sessions

  • Puppeteer

    Browser automation

    --proxy-server -> page.authenticate() -> page.goto()

  • Scrapy

    Crawler framework

    Request queue -> downloader middleware -> rotating exit pool

  • Selenium

    Browser automation

    WebDriver -> auth decision -> Databay gateway

Choose the exit pool after the control path works. Use residential for reputation-sensitive targets or datacenter for throughput.

Residential →Datacenter →

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.