Axios doesn't send headers from request interceptors

Viewed 1083

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?

3 Answers

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.

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.

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});
  }
}
Related