Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use react-router-dom to redirect user when token has expired?

I have a React application that accesses a Flask API. To access some API routes, the user needs to log in. I am using Axios to do the requests. Then, he receives a token which is stored in the local storage. When this token expires and the user makes another request, I want to redirect him to the login page. However, I don't know how I would do it.

I am treating API request errors with Axios response interceptor. It removes the token from the local storage and then should redirect the user to the login page. Since I am using functional components, I could not find an example that fits well (besides downloading another package called history).

I have tried to use the 'useHistory' hook and Redirect from react-router-dom (with a proper BrowserRouter set up), but it doesn't work.

api.js

import axios from "axios"

import { RemoveAuth } from "./Auth"

export const api = axios.create({
    baseURL: "http://localhost:5000/api/",
    timeout: 15000,
})

// more code

api.interceptors.response.use(null, (error) => {

  if(error.response.status === 401){
    RemoveAuth();
  }

  return error;
});

Auth.js

import { useHistory } from "react-router-dom"

export const RemoveAuth = () => {
  let history = useHistory()
  localStorage.clear();
  history.push('/login')
}

routes.js

import React from "react";

import { BrowserRouter, Switch, Route } from "react-router-dom";

import PrivateRoutes from "./PrivateRoutes";


import Dashboard from "../pages/dashboard";

import Login from "../pages/login";
import Logout from "../pages/logout";

const Routes = () => (
  <BrowserRouter>
    <Switch>
      <PrivateRoutes exact path="/dashboard" component={Dashboard} />
      <PrivateRoutes exact path="/logout" component={Logout} />
      <Route exact path="/login" component={Login} />
    </Switch>
  </BrowserRouter>
);

PrivateRoutes.js

import React from "react";

import { Route, Redirect } from "react-router-dom";

import { AuthLogin } from "../services/Auth";

const PrivateRoutes = ({ component: Component, ...rest }) => (
    <Route
      {...rest}
      render={() => (AuthLogin() ? <Redirect to="/login" /> : <Component />)}
    />
);

export default PrivateRoutes;

Thanks in advance for the help!

like image 712
Joao Pedro Barreto Avatar asked Oct 18 '25 06:10

Joao Pedro Barreto


1 Answers

The simplest thing to do is to create your own history object. Something like this:

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

Then in your provider pass in your custom history object:

import { Router } from 'react-router-dom'
import history from './utils/history'

ReactDOM.render(
  <Router history={history}>
    <App />
  </Router>
  document.getElementById('root')
);

This allows you to utilize your history in non-component code. Just import your history object into your Auth.js file and use it:

import { history } from './utils/history'

export const RemoveAuth = () => {
  localStorage.clear();
  history.push('/login')
}

As an added bonus, now your history lives in a place that is easily mock-able, so creating testing around it is more straightforward. You can find more information about creating your own custom history object in the docs.

like image 166
jack.benson Avatar answered Oct 20 '25 19:10

jack.benson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!