0

I am having some issue login the user in my app using vue 3 (vue-cli) and vue-router 4

This is the router.js

import { createRouter, createWebHistory } from 'vue-router';

import store from '../store';

import AuthLayout from "../layouts/AuthLayout";
import DashboardLayout from "../layouts/DashboardLayout";
import PageNotFound from "../views/errors/PageNotFound";

import Login from "../views/auth/Login";
import Logout from "../views/auth/Logout"
import Dashboard from "../views/dashboard/Dashboard";

let routes = [
  {
    path: '/',
    redirect: 'dashboard',
    component: DashboardLayout,
    children: [
      {
        path: '/',
        component: Dashboard,
        name: 'dashboard',
        meta: {
          requiresAuth: true
        }
      },
      {
        path: '/logout',
        component: Logout,
        name: 'logout',
        meta: {
          requiresAuth: true
        }
      },
      {
        path: '/:pathMatch(.*)*',
        component: PageNotFound,
        name: 'page-not-found',
        meta: {
          requiresAuth: true
        }
      }
    ]
  },
  {
    path: '/',
    redirect: 'login',
    component: AuthLayout,
    children: [
      {
        path: '/login',
        component: Login,
        name: 'login',
        meta: {
          requiresVisitor: true
        }
      },
    ]
  }
];

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes: routes,
  linkExactActiveClass: 'active'
});

// eslint-disable-next-line no-unused-vars
router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !store.state.authenticated) {
    return {
      name: 'login',
    }
  }
})

export default router;

I am importing the store in routes to access the state authenticated. When the server auth the user then authenticated = true.

The authenticated (state from vuex) ... it is true now... but it stays at login form. If I force to go in / (dashboard) it return again to login.

The user is logged in.

Anyone have an idea what I am missing in routes.js ???

***** UPDATE *****

Login component

export default {
  name: "Login.vue",
  setup() {
    const axios = inject('$axios')
    const store = useStore()
    const authenticated = computed(() => store.state.authenticated)

    const auth = ref( {
      email: '',
      password: ''
    })

    const authUser = () => {
      axios.get('/api/user').then(response => {
        store.commit('setAuthenticated',true);
        store.commit('setUser', response.data)
      })
    }

    const handleLogin = () => {
      // eslint-disable-next-line no-unused-vars
      axios.post('/login', auth.value).then(response => {
        authUser()
      }).catch(error => {
        console.log(error)       
      })
    }

    onMounted(() => {
      // eslint-disable-next-line no-unused-vars
      axios.get('/sanctum/csrf-cookie').then(response => {
        authUser()
      })
    })

    return { auth, handleLogin, authenticated }
  }
}
Daniel
  • 34,125
  • 17
  • 102
  • 150
calin24
  • 905
  • 3
  • 21
  • 43
  • *When the server auth the user then authenticated = true* - this is where the problem likely is but this isn't shown. – Estus Flask Apr 26 '21 at 19:49
  • @EstusFlask I have updated the post (posted the login component) – calin24 Apr 26 '21 at 20:05
  • I see some potential issues here, but no need to get into unrelated stuff. Can you clarify what you mean by _If I force to go in / (dashboard) it return again to login._ is that redirect done by a `router push` or a manual url change? – Daniel Apr 26 '21 at 20:50
  • what I mean force (is manual url changing) from /login to / – calin24 Apr 26 '21 at 20:52
  • that's what I figured. Also, are you storing the login credentials in localStorage or perhaps a cookie? – Daniel Apr 26 '21 at 20:54
  • and can you share the `setAuthenticated` mutation? – Daniel Apr 26 '21 at 20:55
  • login credentials are used in the login form once (email adn password) => if the credentials are correct => set the authenticated = true (in vuex) – calin24 Apr 26 '21 at 20:56
  • @Daniel the auth mutation is this: `setAuthenticated(state, payload) { state.authenticated = payload; },` ... nothing fancy :) – calin24 Apr 26 '21 at 20:57
  • I see. It looks ok, besides there's no persistence, as the post says. If you open / in location bar, it will obviously reload the page with no auth. But the problem seems to be here `{ path: '/', redirect: 'login',...`. This unconditionally redirects to login as you describe, doesn't it? – Estus Flask Apr 26 '21 at 21:20
  • @EstusFlask the persistence is ok. The value is true in vuex on `authenticated`. I tested on refresh page and output the value in the login form. – calin24 Apr 26 '21 at 21:29

1 Answers1

0

The issue, I believe, is that the authentication state is not persistent. That means, that the data is gone if you redirect (using a manual url change) or refresh.

You can add persistence by

const state = {
  authenticated: localStorage.getItem('authenticated')==='true'; // get authentication from local storage
}
const store = createStore({
  state: state,
  mutations: {
    setAuthenticated(state, payload) {
      state.authenticated = payload;
      localStorage.setItem('authenticated', payload); // sill store 'true' in local storage
    }
  }
})

This will store the authenticated state in your localStorage. It populates the store state.authenticated value on instantiation, and updates on change.

There's some other considerations, such as redirecting

    const authUser = () => {
      axios.get('/api/user').then(response => {
        store.commit('setAuthenticated',true);
        store.commit('setUser', response.data);
        router.push('/'); // <= will redirect after the values are set
      })
    }
Daniel
  • 34,125
  • 17
  • 102
  • 150
  • The persistence is there on store.state.authenticate. If refresh the page I output the value in the login form and is true.... anyway... I set the `router.push({name: 'dashboard'});` in the `authUser` function and now it redirects....but if I change the route (router-link) to another page (ex: /category) and refresh ... it goes back to / (dashboard). I set the `requiresAuth: true` on logout because the user needs to be logged in to log out :) – calin24 Apr 26 '21 at 21:27
  • I have set the state authenticated `authenticated: localStorage.getItem('authenticated')==='true';` as you said and updated it in the mutation `localStorage.setItem('authenticated', payload);` and now it works. I don't get it why because if refresh the page the state `authenticated` was true. If it was the persistence problem it should reset to default value `false` when refresh the page. It is safe to use `localStorage` to store the state `authenticated` ? – calin24 Apr 27 '21 at 08:31
  • I suspect that `authUser` ran and logged in the user after the route executed already – Daniel Apr 27 '21 at 15:30