-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interceptors - how to prevent intercepted messages from resolving as error #266
Comments
Sorry for the delay, I am just seeing this issue. You need to make a return statement from your interceptor which will keep the Promise alive. More or less change your Or if you can't refactor axios.interceptors.response.use(undefined, err => {
let res = err.response;
if (res.status === 401 && res.config && !res.config.__isRetryRequest) {
return new Promise((resolve, reject) => {
refreshLogin(getRefreshToken(),
success => {
setTokens(success.access_token, success.refresh_token)
err.config.__isRetryRequest = true
err.config.headers.Authorization = 'Bearer ' + getAccessToken()
resolve(axios(err.config))
},
error => {
console.log('Refresh login error: ', error)
reject(error)
}
)
});
}
}) |
Nope, doesn't do it. The line "let res = err.response" doesn't work - there's no response in err. If I leave it out, than the success gets triggered - so login happens, but the original request doesn't get retried. |
What version of axios are you using? |
That was with 0.12.0.
|
@dmt0 Did you get this working? |
@heeton Nope, been busy with other things. The solution posted didn't "just work". But it might have been due to some funny behavior in my backend. Will keep you posted... |
You could do something like this: axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const refreshToken = window.localStorage.getItem('refreshToken');
return axios.post('http://localhost:8000/auth/refresh', { refreshToken })
.then(({data}) => {
window.localStorage.setItem('token', data.token);
window.localStorage.setItem('refreshToken', data.refreshToken);
axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
return axios(originalRequest);
});
}
return Promise.reject(error);
}); |
Here, error.response return undefined in 0.14.0 version. |
may you try |
The console.log returns undefined. |
I am pretty sure it should be |
Is this issue resolved? I am using 0.15.2 and running into this weird problem |
@dmt0 The same with you... I am using 0.15.2 ... So, which version is okay for this ? |
I used @geocine example from Oct, 5th 2016. I am using Vue.axios.interceptors.request.use((config) => {
if (store.state.auth) {
config.headers.common['Authorization'] = 'Bearer ' + store.state.token
}
return config
}, function (error) {
// Do something with request error
return Promise.reject(error)
})
Vue.axios.interceptors.response.use((response) => {
return response
}, function (error) {
let originalRequest = error.config
console.log(originalRequest)
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true
Vue.axios.post('/users/token', null).then((data) => {
store.dispatch('authfalse')
store.dispatch('authtruth', data.data)
originalRequest.headers['Authorization'] = 'Bearer ' + store.state.token
return Vue.axios(originalRequest)
})
}
// Do something with response error
return Promise.reject(error)
}) |
is this solved yet? there is no |
In the response interceptor rejection function, the |
is this solved ? im using version 0.15.3 but |
I was able to adapt @rlambertsen example. Worked fine. |
This is also an issue for me - v.0.15.3 - the error is just a callstack error string |
it works here, i'm running axios v0.16.1. The only thing to note is that if you have set this.responseInterceptor = this.axios.interceptors.response.use((response) => response, (error) => {
let value = error.response;
if (value.status === 401 && value.data.message === 'Expired JWT Token'
&& (!value.config || !value.config.renewToken)) {
console.log('Token JWT expiré. Reconnexion ...');
// renewToken performs authentication using username/password saved in sessionStorage/localStorage
return this.renewToken().then(() => {
error.config.baseURL = undefined; // baseURL is already present in url
return this.axios.request(error.config);
}).then((response) => {
console.log('Reconnecté !');
return response;
});
} else if (value.status === 401 && value.config && value.config.renewToken) {
console.log('Echec de la reconnexion !');
if (error.message) {
error.message = 'Echec de la reconnexion ! ' + error.message + '.';
} else {
error.message = 'Echec de la reconnexion !';
}
} else if (value.status === 401) {
console.log('Accès refusé.');
// TODO: We could ask for username/password in a modal dialog...
}
return Promise.reject(error);
}); |
I looking for solution for the past 3 to 4 months on this and still nothing worked. I am using Laravel to return the error and browser is able to identify the 401 (Unauthorized) but no help with axios. The below code consoles axios.interceptors.response.use((response) => response, (error) => {
let value = error.response
console.log(value)
}) |
Can you |
1 similar comment
Can you |
Maybe Laravel (or something else) intercept the error before axios, and reject the promise with another data type ? I'm using axios in a VueJS app, it's currently a tiny app as it's a new project. Try to find out if you have another axios interceptor running before this one ? |
Yes I am using the axios with Vuejs App, This is how I did /* global API_URL */
window.axios = require('axios').create({
baseURL: API_URL,
timeout: false,
params: {} // do not remove this, its added to add params later in the config
})
// Add a request interceptor
/* global window axios */
axios.interceptors.request.use(function (config) {
/* global window Store */
let token = Store.get('jwt.token')
let location = Store.get('location')
// console.log(location.id, location)
if (token) {
config.headers.common['Authorization'] = 'Bearer ' + token
}
// Append location id for every post/get request
if (location) {
if (config.data) {
config.data.location_id = location.id
}
else if (config.params) {
config.params.location_id = location.id
}
}
return config
}, function (error) {
// Do something with request error
return Promise.reject(error)
})
axios.interceptors.response.use((response) => response, (error) => {
console.log(error.config)
}) |
@Toilal I figured out the problem and not sure what could be the fix. If I remove |
I use both and it works. Do you return the right objects in your request
interceptor promise ?
Le 11 avr. 2017 18:55, "vijay kumar" <notifications@github.com> a écrit :
… @Toilal <https://github.com/Toilal> I figured out the problem and not
sure what could be the fix. If I remove
axios.interceptors.request part, it works great. Should we use both
request and response in same call ? if yes do you know a work around ?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#266 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABHJvmxkHSGY0mEXmiygeUW7xViqiiMXks5ru7CGgaJpZM4Hwec2>
.
|
I solved it, the 401 doesn't have |
I had the problem, that Faulty code in request interceptor: axios.interceptors.request.use(config => this.dispatch('refreshAuthToken').then(() => {
// do stuff to set Authorization header
return Promise.resolve(config);
})) Fixed code: axios.interceptors.request.use(config => this.dispatch('refreshAuthToken').then(() => {
// do stuff to set Authorization header
return Promise.resolve(config);
// ensure we resolve config in error case
}), () => Promise.resolve(config)); |
Based on this sample: #450 (comment) I have used this version for refreshing token - as is described on post above. This interceptor is created for prevent refresh token repeatly if it is created more request and you probable want to call this operation only once. This is typescript version but I think it is very similiar to js version. export default class AuthorizationHelper {
authTokenRequest: Promise<any>;
getNewAccessToken() {
const refreshToken = window.localStorage.getItem("refreshToken");
if (!this.authTokenRequest) {
this.authTokenRequest = this.refreshToken(refreshToken);
this.authTokenRequest.then(response => {
this.resetGetAccessTokenRequest();
}).catch(error => {
this.resetGetAccessTokenRequest();
});
}
return this.authTokenRequest;
}
resetGetAccessTokenRequest() {
this.authTokenRequest = null;
}
refreshToken(refreshToken: string): Promise<any> {
return axios.post('/api/token/refresh',
{
refreshToken: refreshToken
});
}
registerAxiosInterceptor() {
axios.interceptors.response.use((response) => {
return response;
}, err => {
const error = err.response;
if (error.status === 401 && error.config && !error.config.__isRetryRequest) {
return this.getNewAccessToken().then(response => {
error.config.__isRetryRequest = true;
//set new access token after refreshing it
axios.defaults.headers.common["Authorization"] = `Bearer ${response.access_token}`;
error.config.headers["Authorization"] = `Bearer ${response.access_token}`;
return axios(error.config);
}).catch(error => {
//refreshing has failed => redirect to login
//clear cookie (with logout action) and return to identityserver to new login
//(window as any).location = "/account/logout";
return Promise.reject(error);
});
}
return Promise.reject(error);
});
}
} |
// for multiple requests
let isRefreshing = false;
let failedQueue = [];
const processQueue = (error, token = null) => {
failedQueue.forEach(prom => {
if (error) {
prom.reject(error);
} else {
prom.resolve(token);
}
})
failedQueue = [];
}
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise(function(resolve, reject) {
failedQueue.push({resolve, reject})
}).then(token => {
originalRequest.headers['Authorization'] = 'Bearer ' + token;
return axios(originalRequest);
}).catch(err => {
return Promise.reject(err);
})
}
originalRequest._retry = true;
isRefreshing = true;
const refreshToken = window.localStorage.getItem('refreshToken');
return new Promise(function (resolve, reject) {
axios.post('http://localhost:8000/auth/refresh', { refreshToken })
.then(({data}) => {
window.localStorage.setItem('token', data.token);
window.localStorage.setItem('refreshToken', data.refreshToken);
axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
processQueue(null, data.token);
resolve(axios(originalRequest));
})
.catch((err) => {
processQueue(err, null);
reject(err);
})
.then(() => { isRefreshing = false })
})
}
return Promise.reject(error);
}); |
What you see in Axios version 0.13.* error response the string returned by the toString method of the error object. In the newer versions, If a response has been received from the server, the error object will contain the response property:
|
I'm trying to make an interceptor for 401 responses that result from expired token. Upon interception I want to login and retry the requests with the new token. My problem is that login is also done asynchronously, so by the time the retry happens, the original promises reject. Is there a way around that? Here's my code:
The text was updated successfully, but these errors were encountered: