Create redux middleware to refresh token in react native app

Spread the love

Redux middleware to refresh token automatically

In your react native app, if you are using token to authenticate with server, you could encounter the token expire issue. The issue is that for example, your token timeout is 1 hour, you open app and leave it for a long time, the token will be expired, if at that moment, you do something which interact with server, those request will be failed because the token is timeout. What you have to do now is that send a refresh token to server to refresh the token, and use that token for new requests to server.

To do it in redux, we create a middle-ware to detect every requests to server. The idea is:

  1. In token object responded from server, it should contain a timeout
  2. Every request from client should go through this middle-ware before sending to server
  3. In this middle-ware, with every requests to server, check the token timeout, if token is expired, hold those request, send request to server to refresh token, wait until received new token, use this new token to send those request to server. If the token is still valid, let it be.

Now, let see the code

import * as types from './authenticationTypes';
import Api from '../libs/api';
import Utils from '../commons/utils';

export default function authMiddleware({ dispatch, getState }) {
  return (next) => (action) => {
    if (typeof action === 'function') {
      let state = getState();
      if(!state) {
        if(state.token && isExpired(state.token)) {
          // make sure we are not already refreshing the token
          if(!state.refreshTokenPromise) {
            return refreshToken(dispatch, state).then(() => next(action));
          } else {
            return state.refreshTokenPromise.then(() => next(action));
          }
        }
      }

    }
    return next(action);
  }
}

function isExpired(token) {
  let currentTime = new Date();
  let expires_date = new Date(token.expires_date);
  return currentTime > expires_date;
}

function refreshToken(dispatch, state) {
  let refreshTokenPromise = Api.post('/token', {
    grant_type: 'refresh_token',
    username: state.token.username,
    refresh_token: state.token.refresh_token
  }, null, true).then(resp => {
    dispatch({
      type: types.DONE_REFRESHING_TOKEN
    });
    dispatch({
      type: types.LOGIN_SUCCESS,
      data: resp
    });
    dispatch({
      type: types.SET_HEADER,
      header: {
        Authorization: resp.token_type + ' ' + resp.access_token,
        Instance: state.currentInstance.id
      }
    });
    return resp ? Promise.resolve(resp) : Promise.reject({
        message: 'could not refresh token'
    });
  }).catch(ex => {
    console.log('exception refresh_token', ex);
    dispatch({
      type: types.DONE_REFRESHING_TOKEN
    });
    dispatch({
      type: types.LOGIN_FAILED,
      exception: ex
    });
  });

  dispatch({
    type: types.REFRESHING_TOKEN,
    // we want to keep track of token promise in the state so that we don't     try to refresh the token again while refreshing is in process
    refreshTokenPromise
  });

  return refreshTokenPromise;
}

Lets go through the code.

  1. Create authMiddleware: every request will go to this middle-ware before sending to server.
refreshTokenPromise: just for make sure that if there are many requests to server at the same time, but we only send one refresh token request to server.
export default function authMiddleware({ dispatch, getState }) {
  return (next) => (action) => {
    // check if token is valid => return to current action
    // otherwise refresh token before returning to current action
    if (typeof action === 'function') {
      let state = getState();
      if(!state) {
        if(state.token && isExpired(state.token)) {
          // make sure we are not already refreshing the token
          if(!state.refreshTokenPromise) {
            return refreshToken(dispatch, state).then(() => next(action));
          } else {
            return state.refreshTokenPromise.then(() => next(action));
          }
        }
      }
    }
    return next(action);
  }
}

2. Create action to refresh token (see the code and comment above)

Note:

  • API is a class which I create to send request to server using Fetch library
  • If you don’t understand the code above, please take a look http://redux.js.org/

Redux middleware to refresh token automatically

Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *