Why is my VueJS Login reloading despite catch being called? - vue.js

I have the following code. The catch() is getting called, I can see the toastr alert. However immediately after the page reloads. Any idea why?
signIn() {
this.$store
.dispatch('auth/login', this.credentials)
.then(() => {
this.$toastr.s('You are successfully logged in')
this.$router.push({ name: 'About' })
})
.catch(() => {
// this.$toastr.e('You are successfully logged in')
this.$toastr.e('Please check the form')
})
}
Login Code:
login({ commit }, data) {
commit(types.AUTH_ERROR_CHANGE, null)
// console.log(process.env.VUE_APP_API_URL);
const url = process.env.VUE_APP_API_URL + '/authentication_token'
return new Promise((resolve, reject) => {
axios
.post(url, data)
.then(response => {
commit(types.AUTH_UPDATE_TOKEN, response.data)
resolve(state)
})
.catch(() => {
commit(types.AUTH_ERROR_CHANGE, 'Incorrect username or password')
reject(state)
})
})
},``

Sorry all, the problem was elsewhere completely.
I had an axios interceptor from previous code:
axios.interceptors.response.use(
data => {
store.commit('general/' + types.LOADING_STOP)
return data
},
error => {
store.commit('general/' + types.LOADING_STOP)
if (
error.response &&
error.response.status &&
error.response.status === 401
) {
// window.location.href = '/login'
}
return Promise.reject(error)
}
I had an old location.href there

Related

redirect after authenticate expired using axios in nuxt js

This is my refresh token plugin
refresh_token.js
const axiosOnResponseErrorPlugin = ({ app, $axios, store }) => {
$axios.onResponseError(err => {
const code = parseInt(err.response && err.response.status)
let originalRequest = err.config
if (code === 401) {
originalRequest.__isRetryRequest = true
const refreshToken = store.state.auth.refresh_token ? store.state.auth.refresh_token : null
if (refreshToken) {
return new Promise((resolve, reject) => {
$axios.post('refresh-token/', {
refresh: refreshToken
})
.then((response) => {
if (response.status === 200) {
let auth = response.data
err.response.config.headers['Authorization'] = `${auth.access}`
}
resolve(response)
})
.catch(e => {
// should jump here after facing error from request
reject(e)
})
})
.then((res) => {
return $axios(originalRequest)
})
.catch(e => {
app.router.push('/')
})
}
}
})
}
export default axiosOnResponseErrorPlugin
My problem is, if refresh token is not expired then it's working fine, but if it is expired then it should redirect to a page which is not doing right now. I couldn't find any way to redirect/push to another router after expiration.
Have any suggestion ?
Here is my solution about this situation ..You have to check your original request also. and for that it will create a loop ..if some how refresh token is failed .So check it with your refresh token URL.
$axios.interceptors.response.use(
response => {
return response;
},
function(error) {
const originalRequest = error.config;
if (error.response.status === 401 && originalRequest.url === "accounts/refresh-token/") {
store.dispatch("clearUserData")
return Promise.reject(error)
}
if (error.response.status === 401 && !originalRequest._retry) {
console.log('originalRequest ', originalRequest)
originalRequest._retry = true;
const refreshToken = localStorage.getItem("UserRefreshToken");
return store.dispatch("refreshToken")
.then(res => {
$axios.defaults.headers.common[
"Authorization"
] = localStorage.getItem("UserToken");
return $axios(originalRequest);
})
}
return Promise.reject(error);
}
);
Here is the complete solution of this question
refresh_token.js
const axiosOnResponseErrorPlugin = ({ app, $axios, store }) => {
$axios.onResponseError(err => {
const code = parseInt(err.response && err.response.status)
let originalRequest = err.config
let explode = originalRequest.url.split("/") // i split the original URL to fulfill my condition
if (code === 401 && explode[explode.length - 2] === "refresh-token") {
app.router.push('/')
}
if (code === 401 && !originalRequest._retry) {
originalRequest._retry = true
const refreshToken = store.state.auth.refresh_token ? store.state.auth.refresh_token : null
if (refreshToken) {
return new Promise((resolve, reject) => {
$axios.post('refresh-token/', {
refresh: refreshToken
})
.then((response) => {
if (response.status === 200) {
let auth = response.data
err.response.config.headers['Authorization'] = `${auth.access}`
}
resolve(response)
})
.catch(e => {
// should jump here after facing error from request
reject(e)
})
})
.then((res) => {
return $axios(originalRequest)
})
.catch(e => {
app.router.push('/')
})
}
}
})
}
export default axiosOnResponseErrorPlugin

Using Axios to retry request after refreshing JWT token in Vuex store

I'm trying to use Axios to retry failed requests due to JWT expiry
So far I have then following request in a method on a Vue component:
getAPI2.get("/api/v1/sessions/",{ headers: headers }).then(response => {
console.log(response);
this.items = response.data.items;
});
This is using the below interceptor when it hits an error
const getAPI2 = axios.create({
baseURL: '/'
})
getAPI2.interceptors.response.use(response => response, err => {
if (err.config && err.response && err.response.status === 401) {
store.dispatch('refreshToken')
.then(access => {
axios.request({
method: 'get',
headers: { Authorization: `Bearer ${store.state.accessToken}` },
url: err.config.url
}).then(response => {
console.log('Successfully got data')
console.log(response)
return response;
}).catch(err => {
console.log('Got the new access token but errored after')
return Promise.reject(err)
})
})
.catch(err => {
return Promise.reject(err)
})
}
})
I'm seeing the data when the request hits an error and goes through the interceptor but I think there's an issue in passing back the response to my component
Apologies if this is obvious, my javascript knowledge is in its infancy
After some playing around I managed to get this working:
const getAPI3 = axios.create({
baseURL: '/'
})
getAPI3.interceptors.response.use( (response) => {
// Return normal response
return response;
}, (error) => {
// Return non auth error
if (error.response.status !== 401) {
return new Promise((resolve, reject) => {
reject(error);
});
}
return store.dispatch('refreshToken')
.then((token) => {
// Make new request
const config = error.config;
config.headers = { Authorization: `Bearer ${store.state.accessToken}` }
return new Promise((resolve, reject) => {
axios.request(config).then(response => {
resolve(response);
}).catch((error) => {
reject(error);
})
});
})
.catch((error) => {
Promise.reject(error);
});
});

Vuex promise reject returns undefined

I want the promise reject to return the error to my method but the response is empty inside my methods then() function, how can i get the error response to be returned to my method for further use or even inside the catch function.
My vuex action
//authAction
login({ commit }, payload) {
new Promise((resolve, reject) => {
user.login(payload.user.email, payload.user.password)
.then(response => {
const user = response.data.user;
// If there's user data in response
if (user) {
const payload = [user]
commit('AUTH_SUCCESS', payload, { root: true })
resolve(response)
} else {
reject({ message: "Sorry, cant login right now" })
}
})
.catch(error => {
console.log(error.response.status)
reject(error)
})
})
}
My method
// Login method
login() {
if (!this.checkLogin()) return;
this.$vs.loading();
const payload = {
checkbox_remember_me: this.checkbox_remember_me,
user: {
email: this.email,
password: this.password
}
};
this.$store
.dispatch("auth/login", payload)
.then(res => {
this.$vs.loading.close();
console.log(res);
})
.catch(error => {
this.$vs.loading.close();
this.$vs.notify({
title: "Error",
text: error.message,
});
});
}
What am i missing?
Thanks in advance!
My solution is to 1. dispatch an action whenever an error is thrown which updates state 2. watch state change in view and do something with it

SecureStore is skipped while I am accessing the login function and returns function error

When I call loginUser function it suppose so access the SecureStore function but instead it is returning the from axios.post method.
Any idea what is going wrong here?
import { SecureStore } from 'expo';
export function loginUser(email, password) {
return function (dispatch) {
return axios.post(SIGNIN_URL, { email, password }).then((response) => {
var { user_id, token } = response.data;
Expo.SecureStore.setItemAsync(user_id, password, options).then(function() {
dispatch(authUser(user_id));
console.log('I am in')
}).catch((error) => {
console.log('Its an error')
dispatch(addAlert("Could not log in."));
});
}).catch((error) => {
dispatch(addAlert("Could not log in."));
});
};
}
The issue is with the way you are constructing your promise chain.
const promiseOne = new Promise((resolve, reject) => {
resolve('p1')
})
const promiseTwo = new Promise((resolve, reject) => {
resolve('p2')
})
promiseOne.then(
(res) => {
console.log('res', res)
return promiseTwo
})
.then((res2) => {
console.log('res2', res2)
})
basically you need to return the call to Expo

How to update view inside axios promise and after store dispatch?

I have a simple vue app where I'm trying to add simple authentication. Inside my login.vue, I use axios to authenticate the user via ajax and store the token returned by the api in the store then redirect to a new page (ex: dashboard.vue).
The problem is that the token is saved but the view is not updated, can't call router.push() ...
Any ideas why isn't it working ? Thanks
Login.vue
methods: {
authenticate () {
var dataLogin = {
email: this.login,
password: this.password
}
var headers = { headers: { 'Content-type': 'application/json', 'Accept': 'application/json' } }
axios.post(config.apiUrl, dataLogin, headers)
.then(response => {
this.$store.dispatch('login', response.data).then(() => {
// if there is no error go to home page
if (!this.$store.getters.error) {
this.$router.push('/')
}
})
})
.catch(error => {
this.errorMessage = error.response.data.message
this.authError = true
})
}
}
The store function just save the token with localStorage
const actions = {
login (context, data) {
context.commit('authenticate', data)
}
}
const mutations = {
authenticate (state, data) {
localStorage.setItem('user-access_token', data.access_token)
}
}
You are calling a then() handler when you dispatch the action.
But your action does not return a promise.
So return a promise in your action as follows:
const actions = {
login (context, data) {
return new Promise((resolve, reject) => {
context.commit('authenticate', data)
resolve()
})
}
}
Also chain your promises for better readability
axios.post(config.apiUrl, dataLogin, headers)
.then(response => {
return this.$store.dispatch('login', response.data)
}).then(() => {
// if there is no error go to home page
if (!this.$store.getters.error) {
this.$router.push('/')
}
})
.catch(error => {
this.errorMessage = error.response.data.message
this.authError = true
})