React - How to Logout when Token is expired (JWT) - BezKoder (2024)

In previous post, we’ve used JWT for token based authentication (register, login, logout) in that, if token is expired, user cannot access restricted resource and he need to click on Logout button to refresh the UI and login again. This tutorial continues to show you how to force logout user when the Token is expired.

Related Posts:
In-depth Introduction to JWT-JSON Web Token
React JWT Authentication (without Redux) example
React + Redux: JWT Authentication example

Using React Hooks:
Handle JWT Token expiration in React with Hooks

Contents

  • How to check JWT Token expiry in React
  • Logout user when token is expired and Route changes
    • react-router-dom v5
    • react-router-dom v6
  • Logout user if token is expired from response status
    • react-router-dom v5
    • react-router-dom v6
  • Conclusion
  • Further Reading
  • Source Code

How to check JWT Token expiry in React

There are two ways to check if Token is expired or not.

  • 1. get expiry time in JWT and compare with current time
  • 2. read response status from the server

I will show you the implementations of both ways.
– For 1, we check the token expiration every time the Route changes and call App component logout method.
– For 2, we dispatch logout event to App component when response status tells us the token is expired.

We’re gonna use the code base for next steps. So you need to read one of following tutorials first:
React JWT Authentication (without Redux) example
React Typescript JWT Authentication (without Redux) example
React + Redux: JWT Authentication example

The Github source code is at the end of the tutorials.

Logout user when token is expired and Route changes

We need to do 2 steps:
– Create a component with react-router subscribed to check JWT Token expiry.
– Render it in the App component.

react-router-dom v5

In src folder, create common/auth-verify.js file with following code:

import React, { Component } from "react";import { withRouter } from "react-router-dom";const parseJwt = (token) => { try { return JSON.parse(atob(token.split('.')[1])); } catch (e) { return null; }};class AuthVerify extends Component { constructor(props) { super(props); props.history.listen(() => { const user = JSON.parse(localStorage.getItem("user")); if (user) { const decodedJwt = parseJwt(user.accessToken); if (decodedJwt.exp * 1000 < Date.now()) { props.logOut(); } } }); } render() { return <div></div>; }}export default withRouter(AuthVerify);

Because we use BrowserRouter, we import withRouter and wrap the component with a HoC. Now props can access the history object’s properties and functions. Then we pass a callback to props.history.listen() for listening every Route changes.

To call a parent App component logOut() method from AuthVerify component, we need to pass the logOut() method as a prop:

<AuthVerify logOut={this.logOut}/>

Let’s put the AuthVerify component into App component like this.

import React, { Component } from "react";import { Switch, Route, Link } from "react-router-dom";...import AuthService from "./services/auth.service";import AuthVerify from "./common/auth-verify";class App extends Component { constructor(props) { super(props); this.logOut = this.logOut.bind(this); this.state = { showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }; } ... logOut() { AuthService.logout(); this.setState({ showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }); } render() { ... return ( <div> <nav className="navbar navbar-expand navbar-dark bg-dark"> ... </nav> <div className="container"> <Switch> <Route exact path={["/", "/home"]} component={Home} /> <Route exact path="/login" component={Login} /> <Route exact path="/register" component={Register} /> <Route exact path="/profile" component={Profile} /> <Route path="/user" component={BoardUser} /> <Route path="/mod" component={BoardModerator} /> <Route path="/admin" component={BoardAdmin} /> </Switch> </div> <AuthVerify logOut={this.logOut}/> </div> ); }}export default App;

react-router-dom v6

From the react-router-dom v6, the support for history has been deprecated. So we need a wrapper (HOC) that can use new useful hooks.

In src folder, create common/with-router.js file with following code:

import { useLocation, useNavigate, useParams } from "react-router-dom";export const withRouter = (Component) => { function ComponentWithRouterProp(props) { let location = useLocation(); let navigate = useNavigate(); let params = useParams(); return <Component {...props} router={{ location, navigate, params }} />; } return ComponentWithRouterProp;};

Next, we create AuthVerify Component that uses location for listening the route change:

common/auth-verify.js

import React, { useEffect } from "react";import { withRouter } from "./with-router";const parseJwt = (token) => { try { return JSON.parse(atob(token.split('.')[1])); } catch (e) { return null; }};const AuthVerify = (props) => { let location = props.router.location; useEffect(() => { const user = JSON.parse(localStorage.getItem("user")); if (user) { const decodedJwt = parseJwt(user.accessToken); if (decodedJwt.exp * 1000 < Date.now()) { props.logOut(); } } }, [location]); return <div></div>;};export default withRouter(AuthVerify);

Finally, we need to pass the logOut() method as a prop in App component:
<AuthVerify logOut={this.logOut}/>

src/App.js

import React, { Component } from "react";import { Routes, Route, Link } from "react-router-dom";...import AuthService from "./services/auth.service";import AuthVerify from "./common/auth-verify";class App extends Component { constructor(props) { super(props); this.logOut = this.logOut.bind(this); this.state = { showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }; } ... logOut() { AuthService.logout(); this.setState({ showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }); } render() { ... return ( <div> <nav className="navbar navbar-expand navbar-dark bg-dark"> ... </nav> <div className="container mt-3"> <Routes> <Route path="/" element={<Home />} /> <Route path="/home" element={<Home />} /> <Route path="/login" element={<Login />} /> <Route path="/register" element={<Register />} /> <Route path="/profile" element={<Profile />} /> <Route path="/user" element={<BoardUser />} /> <Route path="/mod" element={<BoardModerator />} /> <Route path="/admin" element={<BoardAdmin />} /> </Routes> </div> <AuthVerify logOut={this.logOut}/> </div> ); }}export default App;

Logout user if token is expired from response status

First we need to set up a global event-driven system, or a PubSub system, which allows us to listen and dispatch events from independent components.

An Event Bus implements the PubSub pattern, events will be fired from other components so that they don’t have direct dependencies between each other.

We’re gonna create Event Bus with three methods: on, dispatch, and remove.

common/EventBus.js

const eventBus = { on(event, callback) { document.addEventListener(event, (e) => callback(e.detail)); }, dispatch(event, data) { document.dispatchEvent(new CustomEvent(event, { detail: data })); }, remove(event, callback) { document.removeEventListener(event, callback); },};export default eventBus;

on() method attachs an EventListener to the document object. The callback will be called when the event gets fired.
dispatch() method fires an event using the CustomEvent API.
remove() method removes the attached event from the document object.

Next, we dispatch "logout" event in the components when getting Unauthorized response status.

components/board-user.component.js

...import EventBus from "../common/EventBus";export default class BoardUser extends Component { constructor(props) { ... } componentDidMount() { UserService.getUserBoard().then( response => { ... }, error => { this.setState({ content: (error.response && error.response.data && error.response.data.message) || error.message || error.toString() }); if (error.response && error.response.status === 401) { EventBus.dispatch("logout"); } } ); } render() { ... }}

Finally we only need to import EventBus in App component and listen to "logout" event.

react-router-dom v5

src/App.js

import React, { Component } from "react";import { Switch, Route, Link } from "react-router-dom";...import AuthService from "./services/auth.service";import EventBus from "./common/EventBus";class App extends Component { constructor(props) { super(props); this.logOut = this.logOut.bind(this); this.state = { showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }; } componentDidMount() { ... EventBus.on("logout", () => { this.logOut(); }); } componentWillUnmount() { EventBus.remove("logout"); } logOut() { AuthService.logout(); this.setState({ showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }); } render() { ... return ( <div> <nav className="navbar navbar-expand navbar-dark bg-dark"> ... </nav> <div className="container"> <Switch> <Route exact path={["/", "/home"]} component={Home} /> <Route exact path="/login" component={Login} /> <Route exact path="/register" component={Register} /> <Route exact path="/profile" component={Profile} /> <Route path="/user" component={BoardUser} /> <Route path="/mod" component={BoardModerator} /> <Route path="/admin" component={BoardAdmin} /> </Switch> </div> </div> ); }}export default App;

react-router-dom v6

src/App.js

import React, { Component } from "react";import { Routes, Route, Link } from "react-router-dom";...import AuthService from "./services/auth.service";import EventBus from "./common/EventBus";class App extends Component { constructor(props) { super(props); this.logOut = this.logOut.bind(this); this.state = { showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }; } componentDidMount() { ... EventBus.on("logout", () => { this.logOut(); }); } componentWillUnmount() { EventBus.remove("logout"); } logOut() { AuthService.logout(); this.setState({ showModeratorBoard: false, showAdminBoard: false, currentUser: undefined, }); } render() { ... return ( <div> <nav className="navbar navbar-expand navbar-dark bg-dark"> ... </nav> <div className="container mt-3"> <Routes> <Route path="/" element={<Home />} /> <Route path="/home" element={<Home />} /> <Route path="/login" element={<Login />} /> <Route path="/register" element={<Register />} /> <Route path="/profile" element={<Profile />} /> <Route path="/user" element={<BoardUser />} /> <Route path="/mod" element={<BoardModerator />} /> <Route path="/admin" element={<BoardAdmin />} /> </Routes> </div> </div> ); }}export default App;

Conclusion

Today we’ve known two ways to check check jwt token expiry in React and logout user when the Token is expired.

For the code base, you need to read one of following tutorials first:
React JWT Authentication (without Redux) example
React Typescript JWT Authentication (without Redux) example
React + Redux: JWT Authentication example

Using React Hooks instead:
Handle JWT Token expiration in React with Hooks

You can continue to build fullstack Authentication and Authorization system with:
React + Spring Boot: JWT Authentication example
React + Node.js Express: JWT Authentication example

Further Reading

Fullstack CRUD example:
React + Spring Boot + MySQL
React + Spring Boot + PostgreSQL
React + Spring Boot + MongoDB
React + Node.js Express + MySQL
React + Node.js Express + PostgreSQL
React + Node.js Express + MongoDB
React + Django

Simplify import statement with:
Absolute Import in React

Source Code

You can find the complete source code on Github:
React (without Redux).
React Typescript (without Redux).
React + Redux.

React - How to Logout when Token is expired (JWT) - BezKoder (2024)

FAQs

How to handle expired JWT token in React? ›

Handling Expired Tokens:

When a token is expired, we need to remove it from local storage and redirect the user to the login page. Like so: useEffect(() => { if (localStorage. getItem('token')) { const token = localStorage.

How do I handle expired JWT tokens? ›

This typically involves sending a request to a designated endpoint on your server, along with the expired token. Also, you can implement server-side validation on the server-side, verify the expired token and the user's identity. If the token is indeed expired but the user is still authenticated, generate a new token.

How to expire a JWT token on Logout? ›

To invalidate the JWT token upon logout, you can maintain a blacklist or a list of revoked tokens. When a user logs out, add their token to this blacklist. When a request is made with a blacklisted token, it should be rejected.

How to auto logout when session expires in React JS? ›

So what we have done here is we have set the idle time to 5 seconds and warning time to 10 seconds before it logs the user out. Whenever there is no activity by the user for 5 seconds, it pops up a dialog box with a timer countdown of 10 seconds. And automatically the user is logged out after a 10 seconds interval.

What to do if a token is expired? ›

This usually happens when a user session lasts longer than the token's lifespan. To resolve this issue, you can either refresh the token manually or set up an automatic token refresh in your application. Another solution is to increase the token's lifespan, but this could potentially compromise security.

What happens after JWT expires? ›

Once it expires, they'll use their current refresh token to try and get a new JWT. Since the refresh token has been revoked, this operation will fail and they'll be forced to login again. It's this 5 to 10 minute window that freaks everyone out.

Should JWT be invalidated after logout? ›

However, with JWT tokens, once issued, they remain valid until they expire, regardless of whether a user logs out or not. This can pose a security risk, especially when users want to invalidate their tokens for various reasons, such as logging out from a shared device or changing their password.

What is the response code for expired JWT token? ›

Status codes
Status codeResponse
400 Bad Request{ "error": { "code": 400.01, "message": "Missing required attributes" } }
401 Unauthorized{ "error": { "code": 401.01, "message": "Token expired or invalid" } }
401 Invalid Nonce{ "error": { "code": 401.01, "message": "Invalid Nonce" } }
2 more rows

What is the best practice for JWT expiration time? ›

JWTs are self-contained, by-value tokens and it is very hard to revoke them, once issued and delivered to the recipient. Because of that, you should use as short an expiration time for your tokens as possible. A best practice is to set your JWT expiration to minutes or hours at maximum.

How to automatically log out a user after JWT expires on Angular? ›

JWT expiration counter logic

Then we create a new one, let's start it by passing a fake Observable 'of(null)', from which we'll pipe a delay of exactly the amount of time there's left for the JWT to expire and finally, when this occurs, we call our logout method and rout the user to the login page.

Are access tokens still valid after logout? ›

Currently, access tokens are valid until they expire regardless of the fact of the user may log out. In terms of security, invalidating access tokens right after the user logs out would reduce the window of opportunity for an attack.

How to refresh a token in JWT? ›

Because a refresh token is per user and per application, this value will only be returned when an applicationId was provided on the login request and the user is registered to the application. You must explicitly allow generation of refresh tokens when using the Login API. Configure the application. loginConfiguration.

How do I create a logout function in ReactJS? ›

To log-out user from app using ReactJS, we will be using LocalStorage API to store the user login data in the browser storage. When the logout button is clicked it triggers the function to remove the data stored and hence will log the user out clearing all of the user's data.

What is the difference between session expired and timeout? ›

Session Timeout Session expiration, often referred to as a timeout, encompasses two main concepts: inactivity and lifetime. Inactivity refers to a period during which a user doesn't perform any actions, leading to the session's termination after a predetermined duration.

How do you use timeout in ReactJS? ›

setTimeout is a built-in JavaScript function that allows you to schedule the execution of a function after a specified amount of time. Its basic syntax looks like this: setTimeout(callback, delay); callback : A function to be executed after the specified delay.

What is the response for expired token? ›

If you attempt to use an expired token, you'll receive a "401 Unauthorized HTTP" response. When this happens, you'll need to refresh the access token. You shouldn't request a new token for every API call made, as each token is good for an hour and should be reused.

How to refresh a JWT token in React JS? ›

Axios is a popular JavaScript library that simplifies the process of sending asynchronous HTTP requests to the server.
  1. Create Axios Instance. Lets create an axios instance to set BaseURL and header for API call. ...
  2. Add Request Interceptor. ...
  3. Add Response Interceptor. ...
  4. Storing Token Securely.
Apr 19, 2024

How do you handle refresh token expiry? ›

Go to the Settings tab. Under Refresh Token Expiration, enable Absolute Expiration. When enabled, a refresh token will expire based on an absolute lifetime, after which the token can no longer be used. If rotation is enabled, an expiration lifetime must be set.

Top Articles
Why is my site labeled as dangerous in Google Search?
How to financially recover after a divorce
Red Carpet Oil Change Blackstone
Tripadvisor London Forum
Craigslist Kentucky Cars And Trucks - By Owner
Walmart Automotive Number
O'reilly's In Monroe Georgia
Large Pawn Shops Near Me
Lovex Load Data | xxlreloading.com
Defense Immunity 2K23 Meaning
Retail Jobs For Teens Near Me
Craigs List Jonesboro Ar
How To Get Mega Ring In Pokemon Radical Red
Weldmotor Vehicle.com
Spicy Korean Gochujang Tofu (Vegan)
Liquor World Sharon Ma
Skyward Weatherford Isd Login
Cdn Bustednewspaper
Iowa Image Trend
A Flame Extinguished Wow Bugged
Busted Newspaper Hampton County VA Mugshots
Craigslist Yamhill
Ip Address Issue Nad 3303
Chrysler, Dodge, Jeep & Ram Vehicles in Houston, MS | Eaton CDJR
Simply Gorgeous! — Tecnam Completely Refreshed their Best-Selling Light-Sport Aircraft - ByDanJohnson.com
Frontline Education Absence Management Login
Jacksonville Nc Skipthegames
Fototour verlassener Fliegerhorst Schönwald [Lost Place Brandenburg]
02080797947
Bolly2Tolly Sale
359 Greenville Ave Staunton Va
Marshfieldnewsherald Obituary
Leccion 4 Lesson Test
Ice Quartz Osrs
Madden 23 Browns Theme Team
Arsenal’s Auston Trusty: Inspired by Ronaldinho, World Cup dreams and Birmingham loan
Lohud Rockland Obituaries
Jeld Wen Okta Com Login
Easy Homemade Eggnog is So Underrated
Alibaba Expands Membership Perks for 88VIP
Wbap Iheart
Trực tiếp bóng đá Hà Nội vs Bình Định VLeague 2024 hôm nay
Pastel Pink Facetime Icon
Saqify Leaks
Drew Gulliver Bj
Understanding DeFi The Roles, Tools, Risks, and Rewards of -- Alexandra Damsker -- 2024 -- O'Reilly Media -- 9781098120764 -- 79accdb00af9d0f41d97f44fa7970ff1 -- Annas Archive - Biblioteconomia
Skip The Games Buffalo
Ds Cuts Saugus
Fintechzoommortgagecalculator.live Hours
Jailfunds Send Message
Opsahl Kostel Funeral Home & Crematory Yankton
Restaurants Near Defy Trampoline Park
Latest Posts
Article information

Author: Van Hayes

Last Updated:

Views: 6147

Rating: 4.6 / 5 (46 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Van Hayes

Birthday: 1994-06-07

Address: 2004 Kling Rapid, New Destiny, MT 64658-2367

Phone: +512425013758

Job: National Farming Director

Hobby: Reading, Polo, Genealogy, amateur radio, Scouting, Stand-up comedy, Cryptography

Introduction: My name is Van Hayes, I am a thankful, friendly, smiling, calm, powerful, fine, enthusiastic person who loves writing and wants to share my knowledge and understanding with you.