ADVERTISEMENT

How to logout user when token expires in react app

The issue you are facing is simple. Your AuthReducer takes in the initialState only once when its created. Now when you reload your app, everything is initialized again and the expiry is taken care of by your logic. However on Route change It doesn't re-evaluate your initialState.

However what you can do is while using setContext you can check for validation of expiry by decoding the token using jwtDecode and refresh the token if it expired and save in localStorage since this is executed on every request

const authLink = setContext(async () => {
  let token = localStorage.getItem('JWT_Token')
  const { exp } = jwtDecode(token)
  // Refresh the token a minute early to avoid latency issues
  const expirationTime = (exp * 1000) - 60000
  if (Date.now() >= expirationTime) {
    token = await refreshToken()
    // set LocalStorage here based on response;
  }
  return {
    // you can set your headers directly here based on the new token/old token
    headers: {
      ...
    }
  }
})

However since you wish to redirect to login page and not refresh token when the token expired you can make use of custom history object with Routes

src/history.js

import { createBrowserHistory } from 'history';
const history = createBrowserHistory()
export default history;

App.js

import history from '/path/to/history.js';
import { Router } from 'react-router-dom';

<AuthProvider>
  <Router history={history}>
    <div className="App wrapper">
      <Routes/>
    </div>
  </Router>
</AuthProvider>

and then in setContext you could do

import history from '/path/to/history';
const authLink = setContext(async () => {
  let token = localStorage.getItem('JWT_Token')
  const { exp } = jwtDecode(token)
  const expirationTime = (exp * 1000) - 60000
  if (Date.now() >= expirationTime) {
    localStorage.clear();
    history.push('/login');
  }
  return {
    // you can set your headers directly here based on the old token
    headers: {
      ...
    }
  }
})