简体   繁体   中英

React - How to check if JWT is valid before sending a post request?

another noob question. I'm logging in my user to the system using JWT authorization, getting the token and saving it in localstorage and then sending a post request that saves data (its a big form basically). Problem is, the sever is invalidating the token after a given time (20 minutes or so) and so, some of my post requests are returning 401 status . How to verify (and if needed, show a login prompt) before sending the post request? I'm using redux-form to make my forms.

PS: I know I'm supposed to use action creators and such, but I'm still a newbie, so not very good at those stuff.

here's my authentication:

export function loginUser(creds) {

const data = querystring.stringify({_username: creds.username, _password: creds.password});

let config = {
    method: 'POST',
    headers: { 'Content-Type':'application/x-www-form-urlencoded' },
    body: data
};

return dispatch => {
    // We dispatch requestLogin to kickoff the call to the API
    dispatch(requestLogin(creds));

    return fetch(BASE_URL+'/login_check', config)
        .then(response =>
            response.json().then(user => ({ user, response }))
        ).then(({ user, response }) =>  {
            if (!response.ok) {
                // If there was a problem, we want to
                // dispatch the error condition
                dispatch(loginError(user.message));
                return Promise.reject(user)
            } else {
                // If login was successful, set the token in local storage
                localStorage.setItem('id_token', user.token);
                let token = localStorage.getItem('id_token')
                console.log(token);
                // Dispatch the success action
                dispatch(receiveLogin(user));
            }
        }).catch(err => console.log("Error: ", err))
    }
}

and here's the POST request (I'm getting the values object from redux-form )

const token = localStorage.getItem('id_token');
const AuthStr = 'Bearer '.concat(token);

let headers ={
headers: { 'Content-Type':'application/json','Authorization' : AuthStr }
};

export default (async function showResults(values, dispatch) {
axios.post(BASE_URL + '/new', values, headers)
    .then(function (response) {
        console.log(values);
        console.log(response);
    })
    .catch(function (error) {
        console.log(token);
        console.log(values)
        console.log(error.response);
    });
});

PPS: if anyone has any suggestion for improving my code, feel free to comment.

JWT expiration can be checked in two ways. First of all you have to install jsonwebtoken package and require it at the top of your file. Thereafter, you can follow the below ways to check JWT expiration before sending any rest requests.

Option 1

var isExpired = false;
const token = localStorage.getItem('id_token');
var decodedToken=jwt.decode(token, {complete: true});
var dateNow = new Date();

if(decodedToken.exp < dateNow.getTime())
    isExpired = true;

Option 2

const token = localStorage.getItem('id_token');
jwt.verify(token, 'shhhhh', function(err, decoded) {
  if (err) {
    /*
      err = {
        name: 'TokenExpiredError',
        message: 'jwt expired',
        expiredAt: 1408621000
      }
    */
  }
});

Check the error of that method. If it is the TokenExpiredError then that means the token is expired.

Here is a solution with jwt-decode library by comparing the exp attributes in the JWT token with current time. (JWT token is simply a Base64 encoded string)

  • Install jwt-decode ( npm install jwt-decode --save )

     let token = localStorage.getItem(TOKEN); let decodedToken = jwt_decode(token); console.log("Decoded Token", decodedToken); let currentDate = new Date(); // JWT exp is in seconds if (decodedToken.exp * 1000 < currentDate.getTime()) { console.log("Token expired."); } else { console.log("Valid token"); result = true; }

IMPORTANT: jwt-decode doesn't validate the token, any well formed JWT can be decoded. You should validate the token in your server-side logic by using something like express-jwt, koa-jwt, Owin Bearer JWT, etc.

You could also use a middleWare to check if the token has been expired. You even could update the token if it will almost expire. For example, you could do something shown below;

 export function jwtMiddleware({ dispatch, getState }) {
  return (next) => (action) => {
    switch (action.type) {
      case 'CHECK_AUTH_TOKEN' :
        if (getState().auth && getState().auth.token) {
          var tokenExpiration = jwtDecode(getState().auth.token).exp;
          var tokenExpirationTimeInSeconds = (tokenExpiration - moment(Math.floor(Date.now() / 1000)));
          if (tokenExpiration && tokenExpirationTimeInSeconds < 20) {
            history.push(i18next.t('translation:routes.auth.logout'));
          }
        }
      break;
      case 'UPDATE_AUTH_TOKEN' :
        if (getState().auth && getState().auth.token) {
          var tokenExpiration = jwtDecode(getState().auth.token).exp;
          var tokenExpirationTimeInSeconds = (tokenExpiration - moment(Math.floor(Date.now() / 1000)));
          if (tokenExpiration && tokenExpirationTimeInSeconds < 100 && tokenExpirationTimeInSeconds > 20) {
            if (!getState().auth.fetching) {
              return dispatch(refreshAuthToken(getState().auth));
            }
          }
        }
      break;
      case 'REFRESH_AUTH_TOKEN_FAIL' :
        if (getState().auth && getState().auth.token) {
          return dispatch(removeAuthToken(getState().auth)).then(response => {
            history.push(i18next.t('translation:routes.auth.logout'));
          });
        }
      break;
      }
    return next(action);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM