I'm trying to create an Vue 3 with app with JWT authentication and meet an issue with guarding the router using "isAuth" variable from Pinia store to check the access. Eventually Vue router and app in whole loads faster than the Store, that's why I'm always getting "unauthorized" value from the store, but in fact user is logged in and his data is in store. I'll try to describe all the steps that are made to register and login user.
- Registration is made to NodeJS backend and JWT token is created.
- On the login screen user enters email and password, if info is valid he will be logged in and JWT will be saved to localstorage and decoded through JWTdecode, decoded token data will be saved to the store in user variable, and isAuth variable set to true.
- Pinia store has 2 fields in state: user(initially null), and isAuth(initially false).
- In the main App component I'm using async onMounted hook to check the token and keep user logged in by calling the API method, which compares JWT.
- In the Vue router i have several routes that must be protected from the unauthorized users, that's why I'm trying to create navigation guards for them by checking the user information from the store. Problem is, router is created after the setting user info and is always getting the initial state of the user and isAuth variables.
Code:
Store
import { defineStore } from 'pinia';
export const useLoggedInUserStore = defineStore({
id: 'loggedInUser',
state: () => ({
isAuth: false,
user: null
}),
getters: {
getisAuth(state) {
return state.isAuth;
},
getUser(state) {
return state.user;
}
},
actions: {
setUser(user) {
this.user = user;
},
setAuth(boolean) {
this.isAuth = boolean;
}
}
});
App.vue onMounted
onMounted(async () => {
await checkUser()
.then((data) => {
isLoading.value = true;
if (data) {
setUser(data);
setAuth(true);
} else {
router.push({ name: 'Login' });
}
})
.finally((isLoading.value = false));
});
Router guard sample
router.beforeEach((to, from, next) => {
const store = useLoggedInUserStore();
if (!store.isAuth && to.name !== 'Login') next({ name: 'Login' });
else next();
});
I feel that problem is with this async checking, but can't figure out how to rewrite it to load store before the app initialization.
I hope that somebody meet this problem too and can help.
Thanks in advance!