Handling Dropped Auth Headers on Axios Redirects

When an HTTP server responds with a redirect status code (such as 301, 302, or 307), HTTP clients like Axios often strip sensitive headers such as Authorization before making the subsequent request. This article explains why Axios and its underlying transport engines drop authorization headers during redirects, how the behavior differs across environments, and the specific implementation strategies you can use to safely preserve authentication across redirected endpoints.


Why Authorization Headers Are Dropped

The stripping of authorization headers during redirects is a security mechanism defined by standard HTTP specifications (RFC 7235 and RFC 9110). When a client sends credentials to https://api.example.com, sending those same credentials to a redirected destination (such as https://untrusted-external-domain.com) could expose access tokens, API keys, or basic authentication credentials to third parties.

To prevent credential leakage:


How Axios Handles Redirects

The mechanism Axios uses to follow redirects depends directly on the runtime environment:

1. Node.js Environment

In Node.js, Axios relies on the follow-redirects package to manage HTTP/HTTPS redirects. By default, follow-redirects strips sensitive headers—including authorization, cookie, and proxy-authorization—whenever a redirect points to a different hostname or protocol.

2. Browser Environment

In web browsers, Axios relies on the native XMLHttpRequest or fetch APIs. The browser’s network layer handles redirects automatically and transparently. Web applications cannot modify browser-level redirect handling, and modern browsers automatically strip the Authorization header on cross-origin redirects according to the W3C Fetch specification.


Solutions for Preserving Authorization Headers

If you control the redirect target and require authentication credentials to persist, implement one of the following approaches based on your runtime environment.

Approach 1: Disable Automatic Redirects and Follow Manually (Node.js & Edge Runtimes)

The most reliable way to maintain control over headers during redirects is to disable automatic redirect handling by setting maxRedirects: 0. This allows you to inspect the Location header and issue a new request with the required credentials.

const axios = require('axios');

async function secureRedirectRequest(url, token) {
  try {
    const response = await axios.get(url, {
      headers: { Authorization: `Bearer ${token}` },
      maxRedirects: 0, // Prevent Axios from auto-following
      validateStatus: (status) => status >= 200 && status < 400,
    });

    // Check if the response is a redirect (3xx status code)
    if (response.status >= 300 && response.status < 400 && response.headers.location) {
      const redirectUrl = new URL(response.headers.location, url).href;
      
      // Verify destination is a trusted domain before attaching the token
      const isTrustedOrigin = new URL(redirectUrl).hostname === 'trusted-api.example.com';
      
      const newHeaders = isTrustedOrigin 
        ? { Authorization: `Bearer ${token}` } 
        : {};

      return axios.get(redirectUrl, { headers: newHeaders });
    }

    return response;
  } catch (error) {
    throw error;
  }
}

Approach 2: Use beforeRedirect in Node.js

When running in Node.js, you can customize the underlying follow-redirects behavior by providing a beforeRedirect callback function inside your request configuration:

const axios = require('axios');

axios.get('https://example.com/initial-endpoint', {
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN'
  },
  beforeRedirect: (options, responseDetails) => {
    const targetHost = options.hostname;
    
    // Explicitly re-attach the Authorization header if the target host is trusted
    if (targetHost === 'trusted-redirect-target.com') {
      options.headers.Authorization = 'Bearer YOUR_ACCESS_TOKEN';
    }
  }
})
.then(response => console.log(response.data))
.catch(error => console.error(error));

Approach 3: Axios Response Interceptors

You can also automate redirect handling globally across your application by defining an Axios response interceptor that catches 3xx statuses:

const instance = axios.create({
  maxRedirects: 0,
  validateStatus: (status) => status >= 200 && status < 400,
});

instance.interceptors.response.use(async (response) => {
  if (response.status >= 300 && response.status < 400) {
    const redirectUrl = response.headers.location;
    const originalRequest = response.config;

    // Optional: Add host validation here
    return instance({
      ...originalRequest,
      url: redirectUrl,
      headers: {
        ...originalRequest.headers,
        Authorization: originalRequest.headers.Authorization,
      },
    });
  }
  return response;
});

Security Considerations

When re-applying authorization headers to redirected requests: