tbowden
tbowden

Reputation: 1058

Checking the validity of JWT Tokens - beforeEnter

I've got a function that runs 'beforeEnter' in the Vue router to verify that the user has been authenticated, otherwise triggers a message.

It checks to see if a (jwt) token is saved in the localStorage - this works if the user signs out manually, as it removes the token from the localStorage. However when the token expires it still remains in the localStorage so the function thinks ((localStorage.token)) the user is logged in.

The server still blocks any requests made as the token is invalid - so is safe.

How do I check the token's validity on the server side, in the 'beforeEnter' middleware, before the page loads?

Do I need to make an endpoint that checks a tokens validity and returns the result? (I'm using fetch(), however I've seen people use axios interceptors...)

Worth nothing that I'm not using VUEX, and there seems to be more details on that?

function protectedPage(to, from, next) {
  if (localStorage.token) {
    next();
  } else {
    Vue.toasted.show("The session has ended. Please login.", {
      theme: "toasted-primary",
      position: "top-center",
      duration: null,
      action: {
        text: "Login",
        onClick: (e, toastObject) => {
          next("/");
          toastObject.goAway(0);
        }
      }
    });
    next("/");
  }
}

Upvotes: 5

Views: 9141

Answers (2)

Owl
Owl

Reputation: 6853

Since exp is part of the payload, and JWT is just a base64 string, you can just decode it and check the exp time on your Vue app.

This is a function to decode JWT token and get the payload (taken from here)

function parseJwt (token) {
    var base64Url = token.split('.')[1];
    var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
    var jsonPayload = decodeURIComponent(Buffer.from(base64, "base64").toString("ascii").split("").map(function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));

    return JSON.parse(jsonPayload);
};

and check it on your beforeRouteEnter function:

beforeRouteEnter (to, from, next) {
  if (localStorage.token) {
    const jwtPayload = parseJwt(localStorage.token);
    if (jwtPayload.exp < Date.now()/1000) {
        // token expired
        deleteTokenFromLocalStorage();
        next("/");
    }
    next();
  } else {
    next("/");
  }
},

You don't really need to check it on your backend server, since there's no security concern by decoding the JWT token payload and checking it in on the client side. Plus it saves you one HTTP request every time a user access a route.

Upvotes: 9

Tugay İlik
Tugay İlik

Reputation: 3788

You need a backend middleware which bound to each API call and validates user session if still exists and has same tokens.

If the session has been expired or token has been changed and doesn't match with the current user session, you can redirect user to the login page from backend and force him to create a fresh session.

I think you don't need to fetch the authentication for each route entrance, just block the backend api calls and return a message or redirect to the login page. User can still browse the pages with the expired session info but won't be able to perform any fetch or form actions.

Upvotes: 1

Related Questions