Search code examples
javascriptvue.jssecurityroutesvuejs-routing

Secure logging in to a Vue.js SPA


I'm pretty new to Vue.js, I followed lots of tutorials, but one thing bothers me. Let's say I'm building a SPA. The user can log in and then access data using a RESTful API.

So the first step would be to send my login information (username, password) to the API and receive a token. The token would be saved to my vuex and also to the localstorage/cookie so the user stays logged in after a page refresh.

All of the other requests to the API would be signed by the token.

My routes are set up:

const routes = [
    {
        path: '/dashboard', name: 'dashboard', component: Dashboard, meta: { requiresAuth: true }
    },
    {
        path: '/login', name: 'Login', component: Login,
    },
]

I'm using a route guard to protect the /dashboard page from displaying to a non-logged in user:

router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.requiresAuth)) {
        if (!store.getters.loggedIn) {
            next({ path: "/login" })
        } else {
            next();
        }
    } else {
        next();
    }
})

My concern is with the loggedIn getter from vuex store which is implemented this way:

const getters = {
    loggedIn(state) {
         return state.token !== null;
    }
};

Everything is working as it supposed to. I understand that without a access token I won't be able to get data from a server.

But...

I can open the developer tools, put an access_token to my localstorage with a random value, refresh the page and suddenly I can access the /dashboard page.

So my question is, how to avoid this scenario?

My first idea was, to have 2 pages - the login page and the second one which contains the SPA. The authentication would be done via session server-side and the SPA page could be accessed only to a logged in user.

Or is there some standard way to to this, so my SPA can handle this?


Solution

  • as said in the comments, i would create a checkLogin() like this:

    checkLogin() {
          axios
            .get('/webapi/check')
            .then(() => {})
            .catch(err => {
              if (err.response.status === 401) {
                // use a mutation to toggle your "loggedIn" state
                this.$store.commit('loggedIn', false)
                if (this.$route.path !== '/login') {
                  this.$router.push('/login')
                }
              }
            })
        }
    

    and there for u can use ur routeGuard to use the function on each change

    and ofc ur backend should't allow valid backend responses without the token


    UPDATED

    u need a state for loggedIn then u do a mutation to toggle this state depending on how your backend response.