Secure logging in to a Vue.js SPA

832 Views Asked by At

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?

1

There are 1 best solutions below

1
On BEST ANSWER

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.