Redirect to requested page after login using vue-router

Redirectvue.jsVuejs2Vue Router

Redirect Problem Overview


In my application some routes are just accessible for authenticated users.
When a unauthenticated user clicks on a link, for which he has to be signed in, he will be redirected to the login component.

If the user logs in successfully, I would like to redirect him to the URL he requested before he had to log in. However, there also should be a default route, in case the user did not request another URL before he logged in.

How can I achieve this using vue-router?


My code without redirect after login

router.beforeEach(
    (to, from, next) => {
        if(to.matched.some(record => record.meta.forVisitors)) {
            next()
        } else if(to.matched.some(record => record.meta.forAuth)) {
            if(!Vue.auth.isAuthenticated()) {
                next({
                    path: '/login'
                    // Redirect to original path if specified
                })
            } else {
                next()
            }
        } else {
            next()
        }
    }        
)



My login function in my login component

login() {
    var data = {
        client_id: 2,
        client_secret: '**************',
        grant_type: 'password',
        username: this.email,
        password: this.password
    }
    // send data
    this.$http.post('oauth/token', data)
         .then(response => {
             // authenticate the user
             this.$auth.setToken(response.body.access_token,
             response.body.expires_in + Date.now())
             // redirect to route after successful login
             this.$router.push('/')
          })
}

Redirect Solutions


Solution 1 - Redirect

This can be achieved by adding the redirect path in the route as a query parameter.

Then when you login, you have to check if the redirect parameter is set:

  • if IS set redirect to the path found in param
  • if is NOT set you can fallback on root.

Put an action to your link for example:

onLinkClicked() {
    if(!isAuthenticated) {
        // If not authenticated, add a path where to redirect after login.
        this.$router.push({ name: 'login', query: { redirect: '/path' } });
    }
}

The login submit action:

submitForm() {
    AuthService.login(this.credentials)
        .then(() => this.$router.push(this.$route.query.redirect || '/'))
        .catch(error => { /*handle errors*/ })
}

Solution 2 - Redirect

I know this is old but it's the first result in google and for those of you that just want it given to you this is what you add to your two files. In my case I am using firebase for auth.

Router

The key line here is const loginpath = window.location.pathname; where I get the relative path of their first visit and then the next line next({ name: 'Login', query: { from: loginpath } }); I pass as a query in the redirect.

router.beforeEach((to, from, next) => {
    const currentUser = firebase.auth().currentUser;
    const requiresAuth = to.matched.some(record => record.meta.requiresAuth);

    if (requiresAuth && !currentUser) {
        const loginpath = window.location.pathname;
        next({ name: 'Login', query: { from: loginpath } });
    } else if (!requiresAuth && currentUser) next('menu');
    else next();
});

Login Page

No magic here you'll just notice my action upon the user being authenticated this.$router.replace(this.$route.query.from); it sends them to the query url we generated earlier.

signIn() {
    firebase.auth().signInWithEmailAndPassword(this.email, this.password).then(
        (user) => {
            this.$router.replace(this.$route.query.from);
        },
        (err) => {
            this.loginerr = err.message;
        },
    );
},

I am going to be fleshing out this logic in more detail but it works as is. I hope this helps those that come across this page.

Solution 3 - Redirect

Following on from Matt C's answer, this is probably the simplest solution but there were a few issues with that post, so I thought it best to write a complete solution.

The destination route can be stored in the browser's session storage and retrieved after authentication. The benefit of using session storage over using local storage in this case is that the data doesn't linger after a broswer session is ended.

In the router's beforeEach hook set the destination path in session storage so that it can be retrieved after authentication. This works also if you are redirected via a third party auth provider (Google, Facebook etc).

router.js

// If user is not authenticated, before redirecting to login in beforeEach

sessionStorage.setItem('redirectPath', to.path)

So a fuller example might look something like this. I'm using Firebase here but if you're not you can modify it for your purposes:

router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some(x => x.meta.requiresAuth);
  const currentUser = firebase.auth().currentUser;

  if (requiresAuth && !currentUser) {
    sessionStorage.setItem('redirectPath', to.path);
    next('/login');
  } else if (requiresAuth && currentUser) {
    next();
  } else {
    next();
  }
});

login.vue

In your login method, after authetication you will have a line of code that will send the user to a different route. This line will now read the value from session storage. Afterwards we will delete the item from session storage so that it is not accidently used in future (if you the user went directly to the login page on next auth for instance).

this.$router.replace(sessionStorage.getItem('redirectPath') || '/defaultpath');
sessionStorage.removeItem('redirectPath');

A fuller example might look like this:

export default Vue.extend({
  name: 'Login',
  data() {
    return {
      loginForm: {
        email: '',
        password: ''
      }
    }
  },
  methods: {
    login() {
      auth.signInWithEmailAndPassword(this.loginForm.email, this.loginForm.password).then(user => {

        //Go to '/defaultpath' if no redirectPath value is set
        this.$router.replace(sessionStorage.getItem('redirectPath') || '/defaultpath');

        //Cleanup redirectPath
        sessionStorage.removeItem('redirectPath');

      }).catch(err => {
        console.log(err);
      });
    },
  },
});

Solution 4 - Redirect

If route guard is setup as below

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

The redirect query can be extracted and used upon successful login

let searchParams = new URLSearchParams(window.location.search);

if (searchParams.has("redirect")) {
  this.$router.push({ path: `${searchParams.get("redirect")}` });
} else this.$router.push({ path: "/dashboard" });

Solution 5 - Redirect

Another quick and dirty option would be to use local storage like the following:

  1. In your beforeEach, before you redirect to login place the following line of code to save the initial requested path to local storage:

    router.js
    // If user is not authenticated, before redirecting to login
    localStorage.setItem('pathToLoadAfterLogin', to.path)

  2. Then in your login component, upon succesful login, you can redirect to the localStorage variable that you previously created:

    login.vue
    // If user login is successful, route them to what they previously requested or some default route
    this.$router.push(localStorage.getItem('pathToLoadAfterLogin') || 'somedefaultroute');

Solution 6 - Redirect

Much easier with this library and login function is

let redirect = this.$auth.redirect();
this.$auth
  .login({
    data: this.model,
    rememberMe: true,
    redirect: { name: redirect ? redirect.from.name : "homepage",  query: redirect.from.query },
    fetchUser: true
  })

Solution 7 - Redirect

This will help you @Schwesi .

Router.beforeEach(
    (to, from, next) => {
        if (to.matched.some(record => record.meta.forVisitors)) {
            if (Vue.auth.isAuthenticated()) {
                next({
                    path: '/feed'
                })
            } else
                next()
        }
        else if (to.matched.some(record => record.meta.forAuth)) {
            if (!Vue.auth.isAuthenticated()) {
                next({
                    path: '/login'
                })
            } else
                next()
        } else
            next()
    }
);

Solution 8 - Redirect

This worked for me.

 this.axios.post('your api link', {
                token: this.token,              
            })
                .then(() => this.$router.push(this.$route.query.redirect || '/dashboard'))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSchwesiView Question on Stackoverflow
Solution 1 - RedirectV. SamborView Answer on Stackoverflow
Solution 2 - RedirectPhillipView Answer on Stackoverflow
Solution 3 - RedirectJames XabregasView Answer on Stackoverflow
Solution 4 - RedirectaifoduView Answer on Stackoverflow
Solution 5 - RedirectMatt C.View Answer on Stackoverflow
Solution 6 - RedirectFatih TÜZENView Answer on Stackoverflow
Solution 7 - RedirectMohammed AktaaView Answer on Stackoverflow
Solution 8 - Redirectsubash sapkotaView Answer on Stackoverflow