'Axios doesn't send headers from request interceptors

On my front-end I have this Axios code:

import axios from "axios";
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'

const apiUrl = process.server ? `${process.env.FRONT}api/` : '/api/';

const api = axios.create({
  baseURL: apiUrl,
  headers: {
    'Content-Type': 'application/json'
  }
})

api.interceptors.request.use(function (config) {
  const token = localStorage.getItem('token')
  if (token) {
    config.headers.common['Authorization'] = 'Bearer ' + token
  }
  return config;
}, function (error) {
  return Promise.reject(error);
});

export const login = async (payload) => {
  const { data } = await api.post(`login`, payload)
  return data
}

What this code does is just set some headers with token. Then, this request goes to front-end server:

router.post(`/login`, async (req, res) => {
  try {
    const data = await api.post('/login', req.body)
    res.json(data.data)
  } catch (e) {
    res.status(e.response.status).json(e.response.data)
  }
})

If you do console.log(req.headers) here, it's gonna be okay, headers will look like this:

req.headers {
  accept: 'application/json, text/plain, */*',
  'content-type': 'application/json',
  host: 'localhost:8010',
  connection: 'keep-alive',
  'content-length': '898',
  authorization: 'Bearer ...token...',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
...
}

And here is the problem, after that, when request goes to back end, it's captured by middleware auth:

router.post('/login', auth, accountController.login)

This is how this middleware looks like:

import * as jwtService from './../services/jwtService';
import { Request, Response } from 'express';
import { CommonResponse } from "../responses/response";

export default async (req: Request, res: Response, next: any) => {
  try {
    if (req.headers.authorization) {
      const user = await jwtService.getUser(req.headers.authorization.split(' ')[1])
      if (user) next();
      else return CommonResponse.common.unauthorized({ res })
    } else {
      return CommonResponse.common.unauthorized({ res })
    }
  } catch (e) {
    return CommonResponse.common.unauthorized({res});
  }
}

And here is the problem, if you do console.log(req.headers) here you'll see, this:

{
  accept: 'application/json, text/plain, */*',
  'content-type': 'application/json',
  'user-agent': 'axios/0.26.0',
  'content-length': '898',
  host: 'localhost:3000',
  connection: 'close'
}

What happened to my headers?

By the way, if on front end server you do this:

const data = await api.post('/login', req.body, {headers: req.headers})

This is going to work, but still, what happened? Is this how interceptors should work?



Solution 1:[1]

Change your code of interceptors as follows:

api.interceptors.request.use(function (config) {
 const token = localStorage.getItem('token')
 if (token) {
   config.headers['Authorization'] = 'Bearer ' + token
 }
 return config;
}, function (error) {
    return Promise.reject(error);
});

And in middleware you should use Authorization instead of authorization like:

import * as jwtService from './../services/jwtService';
import { Request, Response } from 'express';
import { CommonResponse } from "../responses/response";

export default async (req: Request, res: Response, next: any) => {
  try {
    if (req.headers.Authorization) { // correct this line
      const user = await jwtService.getUser(req.headers.Authorization.split(' ')[1]) // correct this line
      if (user) next();
      else return CommonResponse.common.unauthorized({ res })
    } else {
      return CommonResponse.common.unauthorized({ res })
    }
  } catch (e) {
    return CommonResponse.common.unauthorized({res});
  }
 }

And make sure that you have token in localStorage too and provide feedback if still facing issue.

Solution 2:[2]

There seems to be no issue with code.

Try this demo and it works fine. https://github.com/indolent-developer/axiosDemo

Most probably you are having issue with localstorage. Generally I like to avoid if without else. Can you can some console logs and see it is working fine.

Solution 3:[3]

Maybe the reason behind it is that you're assigning to request.headers.common. It works for me when I assign to req.headers

api.interceptors.request.use(
   (req) => { // I'm using req instead of config just for clarity
      req.headers['Authorization'] = `token ${token}`
      return req;
   },
   (err) => {
      return Promise.reject(err);
   }
);

In your server side, change req.headers.authorization to req.headers.Authorization

import * as jwtService from './../services/jwtService';
import { Request, Response } from 'express';
import { CommonResponse } from "../responses/response";

export default async (req: Request, res: Response, next: any) => {
  try {
    if (req.headers.Authorization) {
      const user = await jwtService.getUser(req.headers.authorization.split(' ')[1])
      if (user) next();
      else return CommonResponse.common.unauthorized({ res })
    } else {
      return CommonResponse.common.unauthorized({ res })
    }
  } catch (e) {
    return CommonResponse.common.unauthorized({res});
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Asad Haroon
Solution 2 indolentdeveloper
Solution 3