How can I logout user when the JWT accessToken expires?
Right now I am using withRouter
as a Higher order component(HOC) to check for route change, but it only works when the user clicks the back button of browser.
I want to check for route changes at every route change not just back button. for example, when the user clicks back to home link, I want to check if the token has expired and then remove token from local Storage.
AuthVerify.js
import React, { useEffect } from "react";
import { withRouter } from "react-router-dom";
const parseJwt = (token) => {
try {
return JSON.parse(atob(token.split(".")[1]));
} catch (e) {
return null;
}
};
const AuthVerify = (props) => {
console.log(props);
useEffect(() => {
props.history.listen(() => {
const token = localStorage.getItem("accessToken");
if (token) {
const decodedJWT = parseJwt(token);
if (decodedJWT.exp * 1000 < Date.now()) {
console.log("expired");
props.logOut();
} else {
}
}
});
}, []);
return <div></div>;
};
export default withRouter(AuthVerify);
Part of App.js
import { Fragment } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import AuthVerify from "../src/utils/AuthVerify";
import "./App.css";
import Home from "./pages/Home";
import Signup from "../src/pages/Signup";
import Login from "../src/pages/Login";
import Test from "./pages/Test";
const logOut = () => {
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
};
function App() {
return (
<Fragment>
<div className="App">
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<PrivateRoute exact path="/test" component={Test} />
<Route exact path="/register" component={Signup} />
<Route exact path="/login" component={Login} />
</Switch>
</BrowserRouter>
</div>
<AuthVerify logOut={logOut} />
</Fragment>
);
}
export default App;
CodePudding user response:
I don't see an issue with your AuthVerify
, it should be called when the location changes. From what I can tell though is that you are rendering the AuthVerify
component outside the router rendering the routes that are changing. The AuthVerify
component needs to be rendered within the router so it's working with the same routing context handling the changing routes.
function App() {
return (
<Fragment>
<div className="App">
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<PrivateRoute exact path="/test" component={Test} />
<Route exact path="/register" component={Signup} />
<Route exact path="/login" component={Login} />
</Switch>
<AuthVerify logOut={logOut} />
</BrowserRouter>
</div>
</Fragment>
);
}
I suggest converting AuthVerify
into a custom hook since it's not rendering content.
const useRouteListener = (cb) => {
const history = useHistory();
useEffect(() => {
return history.listen(cb);
}, [cb, history]);
}
Move the Router
to wrap the App
component and call the useRouteListener
hook and pass your logout token handler. checkToken
here is a callback that would check for the JWT expiration and conditionally invoke your logout procedure.
function App() {
useRouteListener(checkToken);
return (
<Fragment>
<div className="App">
<Switch>
<Route exact path="/" component={Home} />
<PrivateRoute exact path="/test" component={Test} />
<Route exact path="/register" component={Signup} />
<Route exact path="/login" component={Login} />
</Switch>
</div>
</Fragment>
);
}
CodePudding user response:
lets make a use of useLocation hook of react-router-dom
//import the useLocation
import { BrowserRouter, Switch, Route,useLocation } from "react-router-dom";
let location = useLocation()
useEffect(()=>{
//do whatever want to perform, just make sure it is in parent component
logOut()
},[location])
const logOut = () => {
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
};
function App() {
return (
<Fragment>
<div className="App">
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<PrivateRoute exact path="/test" component={Test} />
<Route exact path="/register" component={Signup} />
<Route exact path="/login" component={Login} />
</Switch>
</BrowserRouter>
</div>
<AuthVerify logOut={logOut} />
</Fragment>
);
}