How to Handle Refresh Token When Multiple Requests are going out? How to Handle Refresh Token When Multiple Requests are going out? reactjs reactjs

How to Handle Refresh Token When Multiple Requests are going out?


Hi I have implemented same scenario in react/redux app. But it would help you to achieve the goal. You don't need to check 401 in each API call. Just implement it in your first validation API request. You can use setTimeOut to send refresh token api request before some time of authentication token expiry. So locatStorage will get updated and All axios requests won't get expired token ever.Here is my solution:

in my Constants.js I;m maintaining USER TOKEN in localStorage like this:

 export const USER_TOKEN = {   set: ({ token, refreshToken }) => {      localStorage.setItem('access_token', token);      localStorage.setItem('refresh_token', refreshToken);   },   remove: () => {      localStorage.removeItem('access_token');      localStorage.removeItem('refresh_token'); },   get: () => ({     agent: 'agent',     token: localStorage.getItem('access_token'),     refreshToken: localStorage.getItem('refresh_token'),  }),   get notEmpty() {      return this.get().token !== null;  },};export const DEFAULT_HEADER = {     get: () => ({      'Content-type': 'application/json;charset=UTF-8',       agent: `${USER_TOKEN.get().agent}`,       access_token: `${USER_TOKEN.get().token}`, }),};

on page load, User Validate API request is as follows:

dispatch(actions.validateUser(userPayload)) // First time authentication with user credentials and it return access token, refresh token and expiry time  .then(userData => {    const { expires_in, access_token, refresh_token } = userData    USER_TOKEN.set({          // setting tokens in localStorage to accessible to all API calls      token: access_token,      refreshToken: refresh_token,    });    const timeout = expires_in * 1000 - 60 * 1000; // you can configure as you want but here it is 1 min before token will get expired    this.expiryTimer = setTimeout(() => {  // this would reset localStorage before token expiry timr      this.onRefreshToken();    }, timeout);  }).catch(error => {    console.log("ERROR", error)  });onRefreshToken = () => {   const { dispatch } = this.props;   const refresh_token = USER_TOKEN.get().refreshToken;   dispatch(actions.refreshToken({ refresh_token })).then(userData => {      const { access_token, refresh_token } = userData      USER_TOKEN.set({         token: access_token,          refreshToken: refresh_token,    });  });};

Feel free to ask any questions, The other way is to implement axios abort controller to cancel pending promises. Happy to help with that too !

EDITED - You can maintain axios token source in all you API requests to abort them anytime. maintain axios token source in all of your apis. once you get first promise resolved then you can cancel all other pending APIs request. You can invoke onAbort method in after your first promise gets resolved. See this:

//in your componentclass MyComponent extends Component{isTokenSource = axios.CancelToken.source(); // a signal you can point to any APIcomponentDidMount{   // for example if you're sending multiple api call here        this.props.dispatch(actions.myRequest(payload, this.isTokenSource.token))        .then(() => {            // all good        })        .catch(error => {            if (axios.isCancel(error)) {                console.warn('Error', error);            }        });}onAbortStuff = () => {  // cancel request interceptor    console.log("Aborting Request");    this.isTokenSource.cancel('API was cancelled'); // This will abort all the pending promises if you send the same token in multiple requests, }render(){//}

While in your axios request you can send token like this:

export const myRequest= (id, cancelToken) => {    const URL = `foo`;    return axios(URL, {      method: 'GET',      headers: DEFAULT_HEADER.get(),      cancelToken: cancelToken    }).then(response => {  // handle success  return response.data;  }).catch(error => {  throw error;   });  };

For reference you can this article it is very helpful in understanding of cancel subscriptions. https://medium.freecodecamp.org/how-to-work-with-react-the-right-way-to-avoid-some-common-pitfalls-fc9eb5e34d9e

You can do your routes structuring in this way:index.js

<Provider store={store}>  <BrowserRouter>    <App />  </BrowserRouter></Provider>

App.js:

class App extends Component {state = {    isAuthenticated: false,  };  componentDidMount() {   //authentication API and later you can setState isAuthenticate   }    render() {    const { isAuthenticated } = this.state;    return isAuthenticated ? <Routes /> : <Loading />;  }

If you still find any issue, I'm more than happy to help you with this.