Axios interceptors to validate allowed headers

Axios interceptors to validate allowed headers

Today I want to share a small tip working with CORS and Axios.

It’s very typical in the backend to only allow certain headers, even more so when it defines the CORS-related Access-Control-Request-Headers header used in response to a preflight request. In those cases, if the frontend make a request with an unexpected header the request will be rejected.

This kind of issue mostly happens in the production environments because the browser ignores CORS headers when it fetches data from localhost. That is a problem as nobody will probably detect an issue sending unexpected headers before deploying the code to production.

Axios interceptors

Axios is a widely used library to manage HTTP requests that have an interesting feature: the interceptors are like middlewares where you can execute code before the request (request interceptors) and/or after getting the response (response interceptors)

We will focus on the request interceptors, which are executed before the request to the server is made, this is the perfect place to put our code:

import type { InternalAxiosRequestConfig } from 'axios'

const allowedCorsHeaders = ['Authorization','Origin','X-Requested-With', 'Content-Type','Accept'].map((header) =>
header.toLowerCase())

function validateHeadersInterceptor(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
  // Get the headers we are sending in the requests
  const headers = Object.keys(config.headers).map((header) => header.toLowerCase())
  // Get the headers to send are not in the allowed list
  const invalidHeaders = headers.filter((header) => !allowedCorsHeaders.includes(header))
  
  if (invalidHeaders.length > 0) {
    const msg = `Header(s): ${invalidHeaders.join(', ')} are not allowed.`
    throw new Error(msg)
  }
  return config
}

The validateHeadersInterceptor function gets the config (the current request config) and checks if there are some unexpected headers, if there are thrown an error let the developer know she/he is using an unexpected header.

Using the interceptor is easier as do the:

axios.interceptors.request.use(validateHeadersInterceptor)

The interceptor’s order

You should know that when you have multiple interceptors, the execution order is the inverse of the “use” order

For example:

axios.interceptors.request.use(interceptor1)
axios.interceptors.request.use(interceptor2)
axios.interceptors.request.use(validateHeadersInterceptor)
axios.interceptors.request.use(interceptor3)

the execution order will be interceptor3, validateHeadersInterceptor, interceptor2 and interceptor1. In our validateHeadersInterceptor case we want to check even if another interceptor adds an invalid header. In the example if interceptor1 or interceptor2 add a header to the request we will not notice it as the validator was executed before.

We should ensure our interceptor is “used” first, before any other interceptor.