Skip to content

Vue-Router URL from external source always redirects to “/”

I am running Vue 2 directly off the Vue dev server.

I am trying to enter a vue route (vue-router) from an external url.

<a href="http://localhost:8080/reset_password/{{ reset_email_token }}">Passwort zurücksetzen</a>

For some reason I don’t know, vue-router always redirects my request and handles it as if it comes from “/”, which automatically redirects to “/login”

I found a similiar questions here (https://forum.vuejs.org/t/access-to-a-vue-route-from-external-link/107250) but there is no solution to it.

Has anyone knowledge of this problem and knows how to appraoch a possible fix? Thanks in advance!

My routes.js file:

Vue.use(VueRouter);

const router = new VueRouter({
routes: [
    {
    path: "/login",
    name: "Login",
    component: Login,
    },

    {
      path: "/reset_password/:token", // --> this is the path I want to access from external
      name: "resetPassword",
      component: resetPassword,
    },

    {
      path: "/forgot_password", // --> this also routes to "/" if coming from extern
      name: "forgotPassword",
      component: forgotPassword,
    },

    {
      path: "/", // --> this is where url requests from external end up
      redirect: "login",
      name: "Layout",
      component: Layout,
      meta: { authRequired: true },

      children: [
        {
          path: "/start",
          name: "Start",
          component: Start,
          meta: { authRequired: true },
        },
      ],
    },
    {
      path: "*",
      name: "Error",
      component: Error,
    },
  ],
});

I use the following navigation-guards in my routes.js file.

// check before each route:
// if next route needs auth --> if no grants access to next route
// if current access_token is valid --> if yes grants access to next route
// --> if no: checks if current refresh_token is valid --> if yes grants new access_token and access
// --> if no or if error: sends back to login page

router.beforeEach(async (to, from, next) => {
    let token = localStorage.getItem("token");
    console.log("____________ beforeEach ____________"); //--> see output below
    console.log("from", from);                           //--> see output below
console.log("to", to);                                   //--> see output below

    if (to.meta.authRequired && !isAuthenticated(token)) {
    //await check if refresh works, if so next()
    let refresh_token = localStorage.getItem("refresh_token");
    try {
      const response = await axios.post(
        `${process.env.VUE_APP_BASE_URL}/refresh`,
        { refresh_token: refresh_token },
        {
          headers: {
            Authorization: `Bearer ${refresh_token}`,
          },
        }
      );
      if (response.data) {
        store.dispatch("auth/receiveTokensFromRefresh", {
          new_access_token: response.data.access_token,
          new_refresh_token: response.data.refresh_token,
        });
        next();
        return;
      }
        } catch (e) {
          next({ name: "Login" }, store.dispatch("auth/logoutUser"));
        }

        // next({ name: "Login" }, store.dispatch("auth/logoutUser"));
        next({ name: "Login" }, store.dispatch("auth/logoutUser"));
    }
    next();
});

// check after each route change:
// if coming from login page --> ignore
// how long current access_token still valid
// if under 5 minutes and refresh_token still valid --> grants new access_token

router.afterEach((to, from) => {
    console.log("____________ afterEach ____________"); //--> see output below
    console.log("from", from);                          //--> see output below
    console.log("to", to);                                  //--> see output below
});

beforeEach and afterEach can be commented out and the unexpected behaviour still occurs, therefore they do not cause it. however, their console.log outputs reveal that the request in fact coming from the “/” path:

____________ beforeEach ____________
Routes.js?4195:164 from ObjectfullPath: "/"hash: ""matched: []meta: {}name: nullparams: {}path: "/"query: {}[[Prototype]]: Object
Routes.js?4195:165 to ObjectfullPath: "/login"hash: ""matched: [{…}]meta: {}name: "Login"params: {}path: "/login"query: {}redirectedFrom: "/"[[Prototype]]: Object

____________ afterEach ____________
Routes.js?4195:204 from ObjectfullPath: "/"hash: ""matched: []meta: {}name: nullparams: {}path: "/"query: {}[[Prototype]]: Object
Routes.js?4195:205 to ObjectfullPath: "/login"hash: ""matched: [{…}]meta: {}name: "Login"params: {}path: "/login"query: {}redirectedFrom: "/"[[Prototype]]: Object

Answer

In the meantime I have found a solution for this question.

Switching vue-router mode from ‘hash’ to ‘history’ solved the problem for me.

See here for references on history mode: https://v3.router.vuejs.org/guide/essentials/history-mode.html

const router = new VueRouter({
  mode: "history", // --> added this line
  routes: [ ... ],
});