Search code examples
vuejs3vue-routerauth0pinia

Vue3 - Pinia + Auth0 - isAuthenticated always false


I'm developing a vue3 app using pinia as state manager and auth0 as authprovider.

In my vue router, I've the following code to manage the authentication:

router.beforeEach(async (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
    const authStore = useAuthStore();
    const isLogged = authStore.isLogged();
    if (!isLogged) await handleNotLogged(to, from, next);
    else await handleLogged(to, from, next);
});

async function handleNotLogged(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {
    const authStore = useAuthStore();
    if (to?.query?.code && to?.query?.state) {
        next({ name: '/logged/home' });
    } else {
        await authStore.login();
    }
}
async function handleLogged(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {next()}

here is my authStore

import { defineStore } from 'pinia';
import { User } from '@models/user';
import { useStorage } from '@vueuse/core';
import { RouteLocation } from 'vue-router';
import { createAuth0 } from '@auth0/auth0-vue';
const authService = createAuth0({
    domain: import.meta.env.VITE_APP_AUTH_URL,
    client_id: import.meta.env.VITE_APP_AUTH_CLIENT_ID,
    redirect_uri: `${window.location.origin}`,
});

const defaultUserData = {} as User;
const defaultLastRoute = { path: '/' } as RouteLocation;
export const useAuthStore = defineStore('AuthStore', {
    state: () => ({
        userData: useStorage('userData', defaultUserData, localStorage),
        lastRoute: useStorage('lastRoute', defaultLastRoute, localStorage),
        authService,
    }),
    actions: {
        isLogged(): boolean {
            try {
                return this.authService.isAuthenticated;
            } catch (error) {
                return false;
            }
        },
        async login(): Promise<boolean> {
            try {
                await this.authService.loginWithRedirect();
                return true;
            } catch (error) {
                console.error(error);
                return false;
            }
        },
        async logout(): Promise<boolean> {
            try {
                await this.authService.logout();
                return true;
            } catch (error) {
                console.error(error);
                return false;
            }
        },
    },
});

And also my main.ts

import App from './App.vue';
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import { registerPlugins } from '@plugins';
import { useAuthStore } from '@store/auth';
import router from '@router';
import vuetify from './plugins/vuetify';

async function main() {
    const app = createApp(App);
    registerPlugins();
    const pinia = createPinia();
    app.use(pinia);
    const authStore = useAuthStore();
    const { authService } = authStore;
    app.use(authService);
    app.use(router);
    app.use(vuetify).mount('#app');
}
main();

The problem is that everytime the beforeEach is triggered, the auth0 isAuthenticated returns false. Even when i've just succesfully logged.

I've searched for some answers, and some said that ewhen there is a code and state in query params we should call the auth0.handleRedirectCallback but there's a note in the method saying

Note: The Auth0-Vue SDK handles this for you, unless you set skipRedirectCallback to true. In that case, be sure to explicitly call handleRedirectCallback yourself.

PS: The application in auth0 is configured as Single Page Application


Solution

    1. Create and register the Vue3-Auth0 component in the main.js/ts:

      import { createAuth0 } from "@auth0/auth0-vue";
      export const auth0 = createAuth0({...});
      app.use(auth0);
      
    2. In the main component, verify if Auth0 is loading:

      <script setup>
        ...
        import { useAuth0 } from "@auth0/auth0-vue";
        const { isLoading } = useAuth0();
        ...
      </script>
      <template>
        <router-view v-if="!isLoading"></router-view>
        <div v-else>Loading</div>
      </template>
      

    If Auth0 is loading then isAuthenticated will be false.