DEV Community

KrakMutexx
KrakMutexx

Posted on

Demystifying Axios Interceptors: The Front end's Security Checkpoint

Almost every front end developer uses Axios, but very few truly understand what is going on under the hood. Most of us just copy and paste a block of configuration code from Stack Overflow to make our API calls work, but when it comes to implementing it securely, that blind copy-pasting is a massive risk.

When I first started implementing Axios, I didn't understand how Interceptors actually worked. I understood the basic Client-Server model and the concept of Requests and Responses, but I couldn't visualize what Axios was doing in the middle of that transaction.

Then I realized something that changed my perspective completely: If you are into cyber security, think of an Axios Interceptor like a local proxy—a mini Burp Suite living inside your front end.

In software architecture terms, it acts as a Middle-ware. It is a checkpoint that catches every outgoing request before it leaves your browser, and every incoming response before it reaches your components. The main idea is to intercept, read, and manipulate data (like User-Agents, authentication tokens, or custom headers) in a centralized place.

Assuming you already have Axios installed (if not, check the official documentation), let's build this the right way.

Step 1: Creating the Instance

Instead of importing Axios globally and polluting every request, we create a dedicated instance. This keeps our code clean and centralizes our core configuration.

import axios from 'axios';

// Always use environment variables for your base URLs
const baseURL = process.env.REACT_APP_API_BASE_URL || "https://api.example.com";

const axiosInstance = axios.create({
  baseURL: baseURL,
  timeout: 10000, // Never leave requests hanging forever
  headers: {
    "Content-Type": "application/json"
  }
});

Enter fullscreen mode Exit fullscreen mode

Step 2: The Request Interceptor (The Outbound Customs)

This is where we manipulate the request before it hits the network. Instead of manually injecting the Authorization header in 50 different API calls, we do it here once.

axiosInstance.interceptors.request.use(
  (config) => {
    // Injecting custom tracking or security headers
    config.headers["X-Client-Version"] = "AxiosBlog/1.0"; 
    config.headers["X-Request-ID"] = Math.random().toString(36).substring(2); 

    // Fetching the token and injecting it into the header
    const token = localStorage.getItem("authToken");
    if (token) {
      config.headers["Authorization"] = `Bearer ${token}`;
    }

    return config;
  },
  (error) => {
    // Handle request setup errors
    return Promise.reject(error);
  }
);
Enter fullscreen mode Exit fullscreen mode

A Quick AppSec Reality Check

Storing a JWT in local Storage makes it fully accessible to JavaScript, meaning any Cross-Site Scripting (XSS) vulnerability in your app will allow an attacker to steal that token. In a truly secure, enterprise-grade application, you shouldn't need a Request Interceptor to attach tokens at all. You should use HttpOnly Cookies, which the browser attaches automatically, making them invisible to malicious JS scripts.

Step 3: The Response Interceptor (The Inbound Customs)

You mentioned Requests and Responses earlier. While the Request interceptor handles outgoing traffic, the Response interceptor is critical for handling inbound errors globally.

This is where you handle token expiration (the famous 401 error) so your user doesn't end up staring at a broken UI.

axiosInstance.interceptors.response.use(
  (response) => {
    // Any status code that lies within the range of 2xx triggers this function.
    // We just pass the data through cleanly.
    return response;
  },
  (error) => {
    // Any status codes that falls outside the range of 2xx triggers this function.

    if (error.response && error.response.status === 401) {
      console.warn("[Security] Unauthorized access or expired token detected.");
      // Here you would trigger your logout logic, clear the state, 
      // or attempt to use a Refresh Token.

      // Example: 
      // localStorage.removeItem("authToken");
      // window.location.href = '/login';
    }

    if (error.response && error.response.status === 403) {
      console.error("[Security] Forbidden. User lacks privileges.");
    }

    return Promise.reject(error);
  }
);

export default axiosInstance;
Enter fullscreen mode Exit fullscreen mode

The Takeaway

Interceptors are not just "React tricks" or "clean code patterns." They are the gatekeepers of your frontend's network layer. By centralizing your request and response logic, you reduce the surface area for bugs, make your API calls predictable, and most importantly, you gain a single point of control to audit your outgoing headers and incoming security errors.

Stop writing custom fetch logic in every component. Set up your middleware, configure your aduana, and let the interceptor do the heavy lifting.

Top comments (0)