An implemented interceptor is set up to catch 401 errors in case the access token expires. When it does expire, it attempts to use the refresh token to obtain a new access token. Any other calls made during this process are queued until the access token is validated.
Everything is functioning smoothly with this setup. However, when processing the queue using Axios(originalRequest), the initially attached promises are not being executed. An example of this issue can be seen below.
Current interceptor code:
Axios.interceptors.response.use(
response => response,
(error) => {
const status = error.response ? error.response.status : null
const originalRequest = error.config
if (status === 401) {
if (!store.state.auth.isRefreshing) {
store.dispatch('auth/refresh')
}
const retryOrigReq = store.dispatch('auth/subscribe', token => {
originalRequest.headers['Authorization'] = 'Bearer ' + token
Axios(originalRequest)
})
return retryOrigReq
} else {
return Promise.reject(error)
}
}
)
Refresh Method (Utilizing the refresh token to acquire a new access token)
refresh ({ commit }) {
commit(types.REFRESHING, true)
Vue.$http.post('/login/refresh', {
refresh_token: store.getters['auth/refreshToken']
}).then(response => {
if (response.status === 401) {
store.dispatch('auth/reset')
store.dispatch('app/error', 'You have been logged out.')
} else {
commit(types.AUTH, {
access_token: response.data.access_token,
refresh_token: response.data.refresh_token
})
store.dispatch('auth/refreshed', response.data.access_token)
}
}).catch(() => {
store.dispatch('auth/reset')
store.dispatch('app/error', 'You have been logged out.')
})
},
Subscribe method in auth/actions module:
subscribe ({ commit }, request) {
commit(types.SUBSCRIBEREFRESH, request)
return request
},
Along with the Mutation:
[SUBSCRIBEREFRESH] (state, request) {
state.refreshSubscribers.push(request)
},
Here is an example action:
Vue.$http.get('/users/' + rootState.auth.user.id + '/tasks').then(response => {
if (response && response.data) {
commit(types.NOTIFICATIONS, response.data || [])
}
})
If this request was added to the queue because the refresh token had to fetch a new token, I would like to include the original then() function:
const retryOrigReq = store.dispatch('auth/subscribe', token => {
originalRequest.headers['Authorization'] = 'Bearer ' + token
// I would like to attach the original .then() here as it contained critical functions to execute after the request completion, typically involving mutating the store.
Axios(originalRequest).then(//if then present attache here)
})
Once the access token has been refreshed, the queue of requests is processed:
refreshed ({ commit }, token) {
commit(types.REFRESHING, false)
store.state.auth.refreshSubscribers.map(cb => cb(token))
commit(types.CLEARSUBSCRIBERS)
},