Vue SPA, router guard with redirect after login
Tags: vue, vuex, javascript, tutorial
Published: 2018-10-10 12:59:05

---
title: "Vue SPA, router guard with redirect after login"
tags: vue, vuex, JavaScript, tutorial
cover_image: "https://hgill.io/images/vuex.png"
published: true
---

#### Originally published on my [blog](https://hgill.io)
While making [Let's Organise](https://letsorganise.uk "Let's Organise Homepage") SPA(Single page Application) we bumped into the issue of properly checking Auth and redirecting when a user visited a route that required Authentication. If User is authenticated then go to the requested page or redirect to `/login` page. Once the user has successfully logged in redirect them back to the requested page.

Vue Router has something called [Navigation Guards](https://router.vuejs.org/en/advanced/navigation-guards.html 'Navigation Guards') to the rescue, that you can use as hook before every route or selected routes. Navigation Guard is just a plain function and it works like the following.

<!-- more -->
```js
function guard(to, from, next){
    if(store.state.auth.loggedIn) {
        // or however you store your logged in state
        next(); // allow to enter route
    } else{
        next('/login'); // go to '/login';
    }
}
...
// later in the guarded routes
export default [{
    path: '/membership',
    beforeEnter: guard, // Using guard before entering the route
    component: require('layouts/membershipLayout').default,
    children: [
      { path: '', component: require('pages/membership').default },
      ...
    ]
  }...
  ]
```
Code above invokes the `guard` function at before enter hook and does a basic check and redirection. But really what you need is for the router to remember where user started the route, and also check wether user is already authenticated (maybe in another tab). 

Our application uses JWT(JSON Web Token) to authenticate Users. The JWT is not stored with client side JavaScript but in a secure https cookie. This means that the application JavaScript can't tell wether that token is valid or is even if it exists for that matter. This design requires at least one round trip to the server to validate the token.

In case of User being already authenticated in another tab, redirecting to login page is not a great user experience. So you can think of the flow lik following.

### Router flow logic

![alt text](https://hgill.io/images/code/vuex-flowchart.svg "Logic flow of guard Function")

We want to execute the logic flow above before every guarded route is visited. We have a place holder variable `entryUrl` to keep track of url user entered the site with initially set to `null`. Then we check if we are logged in our application keeps a variable in the `Vuex` state, If logged in then we check if the `entryUrl` variable is not set, then simply go to the next route as normal. Otherwise we redirect to that `entryUrl` and set the variable to `null` again.

If the Vuex logged in variable not set to true,(this could be if user just visited a url without going through login page) in then we invoke a call to the server to check if user is already authenticated.
then check for authentication, if yes go to the route. If every check fails then we store the initial url visited by the user in `entryUrl` variable and redirect user to 'login page'.


Corresponding code to the above model looks something like. 

```js
// routes.js

import store from '../store';

let entryUrl = null;

const guard = async (to, from, next) => {
  if (store.state.auth.loggedIn) {
    if (entryUrl) {
      const url = entryUrl;
      entryUrl = null;
      return next(url); // goto stored url
    } else {
      return next(); // all is fine
    }
  }

  await store.dispatch('checkAuth'); 
  // we use await as this async request has to finish 
  // before we can be sure

  if (store.state.auth.loggedIn) {
    next();
  } else {
    entryUrl = to.path; // store entry url before redirect
    next('/login');
  }
};
```
Say hello if you like on [Twitter](https://Twitter.com/mygnu_)