Axios: Updating auth headers on every request?

Created on 25 Feb 2018  ·  10Comments  ·  Source: axios/axios

Hello guys,

I made a new instance of the axios which I use for the protected api resources and I attached auth header with token to it, but the problem is if I go to the console and delete tokem from localStorage, axios is still sending it as the instance was not updated.

Is there a solution so my auth headers in the instance can check for token in localStorage in every request?

Thanks!

Most helpful comment

I have used interceptors for this purpose. If the base URL of the request is to my API I add the auth header (to prevent sending credentials to third parties). This is run on each request so if the token changes (for example as a result of a token refresh) then the next request picks up the new token. I also ensure I check for existing values in the request to allow overriding of the header from the call site if that happened to be necessary for whatever reason.

axios.interceptors.request.use(
  config => {
    if (config.baseURL === baseApiAddress && !config.headers.Authorization) {
      const token = getToken();

      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
    }

    return config;
  },
  error => Promise.reject(error)
);

All 10 comments

I have a similar use case where it would be great if the passed headers would be evaluated lazily for every request.

Thought:
Instead of passing the headers hash eagerly as an object (axios.create({headers: {...}}) we could pass a function that returns the headers (axios.create({headers: () => {...}}) which would be evaluated before the request is sent.

What do you think?
Edit: This is a proposal, I dont think this works at the moment.

I ran into the same use case. What I ended up doing in the short term was use the transformRequest function. Definitely a hack and would love to assist implementing a proper lazy-loading approach into the codebase.

See below for the code snippet. auth() gets the logged in user's token if available.

let HTTP = axios.create({
  baseURL: baseurl,
  transformRequest: [function (data, headers) {
    headers['Authorization'] = auth()
    return JSON.stringify(data)
  }],
  headers: {
    'Content-Type': 'application/json'
  }
})

I have used interceptors for this purpose. If the base URL of the request is to my API I add the auth header (to prevent sending credentials to third parties). This is run on each request so if the token changes (for example as a result of a token refresh) then the next request picks up the new token. I also ensure I check for existing values in the request to allow overriding of the header from the call site if that happened to be necessary for whatever reason.

axios.interceptors.request.use(
  config => {
    if (config.baseURL === baseApiAddress && !config.headers.Authorization) {
      const token = getToken();

      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
    }

    return config;
  },
  error => Promise.reject(error)
);

@mattstrayer can you show me the getToken() method? Do you storage your token in localStorage or AsyncStorage(React Native)? Thanks in advance!

I ended up with this.

axios.create({
  baseURL: '<your-api>',
  headers: {
    Authorization: {
      toString () {
        return `Bearer ${localStorage.getItem('token')}`
      }
    }
  }
})

I'm not sure whether it works for any case.

My http.js file:

import axios from 'axios';
import {store} from './store';

const http = axios.create ({
  baseURL: process.env.VUE_APP_ROOT_API,
  timeout: 1000,
  headers: {'Content-Type': 'application/json'},
});

http.interceptors.request.use (
  function (config) {
    const token = store.token;
    if (token) config.headers.Authorization = `Bearer ${token}`;
    return config;
  },
  function (error) {
    return Promise.reject (error);
  }
);

export default http;

My store, a simple get/set "class"

export const store = {
    _username: '',
    _email: '',
    _token: '',

    isLogged () {
      return this.token
    },

    set username (str) {
      this._username = str
      localStorage.setItem('username',str)
    },
    get username () {
      return this._username || localStorage.getItem('username')
    },

    set email (str) {
      this._email = str
      localStorage.setItem('email',str)
    },
    get email () {
      return this._email || localStorage.getItem('email')
    },

    set token (str) {
      this._token = str
      localStorage.setItem('token',str)
    },
    get token () {
      return this._token || localStorage.getItem('token')
    }

  }

My user service "class":

import http from './http'

export const user = {
  ping: () => http.get('/users/ping'),
  save: (user) => http.post('/users', user)
}

and finnaly, my implementation:

import {user} from '@/services'

 user.ping().then( r => {
      console.log(r.data)
    })

btw, process.env.VUE_APP_ROOT_API and @/services are Vue things...

Result:
image

@danielschmitz thanks for that example!!

Looks like y'all figured this out and that it isn't a bug, so I'm closing this out 🙂

I found it useful to wrap the interceptor in async/await to ensure my token was set before the API call was triggered:

http.interceptors.request.use (
  async (config) => {
    const token = await getToken(); // slightly longer running function than example above
    if (token) config.headers.Authorization = `Bearer ${token}`;
    return config;
  },
  (error) => {
    return Promise.reject (error);
  }
);

I have used interceptors for this purpose. If the base URL of the request is to my API I add the auth header (to prevent sending credentials to third parties). This is run on each request so if the token changes (for example as a result of a token refresh) then the next request picks up the new token. I also ensure I check for existing values in the request to allow overriding of the header from the call site if that happened to be necessary for whatever reason.

axios.interceptors.request.use(
  config => {
    if (config.baseURL === baseApiAddress && !config.headers.Authorization) {
      const token = getToken();

      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
    }

    return config;
  },
  error => Promise.reject(error)
);

Interceptor seems like the most elegant solution

Was this page helpful?
0 / 5 - 0 ratings