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.
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!
So I just met this problem and fixed it thanks to this solution
As it says, the router gets instantiated before App.vue
is fully mounted so check the token in beforeEach
instead, like:
router.beforeEach(async (to, from, next): Promise<void> => {
const user = useUser();
await user.get();
console.log(user) // user is defined
if (to.meta.requiresAuth && !user.isLoggedIn) next({ name: "home" }); // this will work
By the way instead of having an action setAuth
you could just use your getter isAuth
checking if user
is not null, like:
isAuth: (state) => state.user !== null
Also it's not recommended to store a JWT in the local storage as if you're site is exposed to XSS attacks the token can be stolen. You should at least store it in an HttpOnly cookie (meaning it's not accessible from JavaScript), it's super easy to do with Express.