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!
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:
@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
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.