How to develop a session-based timeout on react.js

react-session.jpg What is Session A session is a time duration where a user interacts or performs activities with an app. For eg: when a user opens Google mail and log in to view his email and after completing the activities he logs out. The time between login and logout is a session. In this tutorial, I am going to take you through how to develop a session-based timeout in react.js.

Why use Session Timeout Session Timeout is generally utilized due to security reasons in a web application. To avoid unnecessary API calls or misuse the user info. Web applications are always vulnerable to security attacks. So, the longer the user is idle the more chances for the hackers to inject malicious code. Sometimes, if there is an API call at regular interval to get the refreshed information. it would not be necessary to call the API if the user is idle. To begin we have to get the starter code at github.com/JamesUgbanu/react-session-timeou..

Step 1: Clone the repo

clone repo.PNG

Run npm install to install all the necessary dependencies. Run npm start, Go to your browser and make sure the starter looks like below. Do not worry, If you can't get your starter app ready, you can always send me a mail.

react session timeout template.PNG

For those who were able to get it ready. Good job :) Next, We set up two (2) components, SessionTimeout.js and SessionTimeoutDialog.js. Before we do that, I will like to explain what each dependency we install does.

@material-ui/core is used for UI design Clsx is used to combine CSS And finally, we will be making use of a dependency to track when the user is idle.

npm install react-idle-timer - save to install

Create a file named SessionTimeout.js and SessionTimeoutDialog.js in your src folder.

SessionTimeoutDialog will house the session component dialog. SessionTimeoutDialog.js should look like below. You could style it to suit your app design.

SessionTimeoutDialog.js

import React from "react";
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Typography,
makeStyles,
Slide
} from "@material-ui/core";
import clsx from "clsx";
import red from "@material-ui/core/colors/red";
const useStyles = makeStyles(() => ({
dialog: {
borderRadius: 0
},
button: {
borderRadius: 0,
textTransform: "none",
padding: 5
},
logout: {
color: "#fff",
backgroundColor: red[500],
"&:hover": {
backgroundColor: red[700]
}
},
countdown: {
color: red[700]
}
}));
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
const SessionTimeoutDialog = ({  open, countdown, onLogout,onContinue }) => {
const classes = useStyles();
return (
<Dialog
open={open}
classes={{ paper: classes.dialog }}
TransitionComponent={Transition}>
<DialogTitle>
Session Timeout
</DialogTitle>
<DialogContent>
<Typography variant="body2">
The current session is about to expire in{" "}
<span className={classes.countdown}>{countdown}</span> seconds.
</Typography>
<Typography variant="body2">{`Would you like to continue the session?`}</Typography>
</DialogContent>
<DialogActions>
<Button
onClick={onLogout}
variant="contained"
className={clsx(classes.logout, classes.button)}>
Logout
</Button>
<Button
onClick={onContinue}
color="primary"
variant="contained"
className={classes.button}>
Continue Session
</Button>
</DialogActions>
</Dialog>
);
}
export default SessionTimeoutDialog;

We can now proceed with the functionality of the session timeout. If you don't understand how material-ui works, you can read up here https://material-ui.com/. Also, this tutorial expects you to be conversant with react hooks https://reactjs.org/docs/hooks-intro.html

Inside SessionTimeout.js we want to create some functions such as clearSessionTimeout, clearSessionInterval, handleLogout, handleContinue, onActive and onIdle.

clearSessionTimeout as the name indicates is to clear/reset the session clearSessionInterval reset time interval used for the countdown timer handleLogout logs users out. handleContinue allows the user to continue with the session. onActive clears SessionTimeout and clearSessionInterval when Session timeout dialog is active. onIdle opens session dialog and set time interval

SessionTimeout.js

import React, { useRef, useState } from "react";
import IdleTimer from "react-idle-timer";
import SessionTimeoutDialog from "./SessionTimeoutDialog";
let countdownInterval;
let timeout;
const SessionTimeout = ({isAuthenticated, logOut}) => {
const [timeoutModalOpen, setTimeoutModalOpen] = useState(false);
const [timeoutCountdown, setTimeoutCountdown] = useState(0);
const idleTimer = useRef(null);
const clearSessionTimeout = () => {
clearTimeout(timeout);
};
const clearSessionInterval = () => {
clearInterval(countdownInterval);
};
const handleLogout = async (isTimedOut = false) => {
try {
setTimeoutModalOpen(false);
clearSessionInterval();
clearSessionTimeout();
logOut();
} catch (err) {
console.error(err);
}
};
const handleContinue = () => {
setTimeoutModalOpen(false);
clearSessionInterval();
clearSessionTimeout();
};
const onActive = () => {
if (!timeoutModalOpen) {
clearSessionInterval();
clearSessionTimeout();
}
};
const onIdle = () => {
const delay = 1000 * 1;
if (isAuthenticated && !timeoutModalOpen) {
timeout = setTimeout(() => {
let countDown = 10;
setTimeoutModalOpen(true);
setTimeoutCountdown(countDown);
countdownInterval = setInterval(() => {
if (countDown > 0) {
setTimeoutCountdown(--countDown);
} else {
handleLogout(true);
}
}, 1000);
}, delay);
}
};
return (
<>
<IdleTimer
ref={idleTimer}
onActive={onActive}
onIdle={onIdle}
debounce={250}
timeout={5000}
/>
<SessionTimeoutDialog
countdown={timeoutCountdown}
onContinue={handleContinue}
onLogout={() => handleLogout(false)}
open={timeoutModalOpen}
/>
</>
);
}
export default SessionTimeout;

We now have SessionTimeoutDialog and SessionTimeout setup. We will now import SessionTimeOut component then pass isAuthenticated state and handleClick function as props.

App.js

import React, { useState } from 'react';
import {
Container,
Box,
Button,
makeStyles
} from '@material-ui/core';
import logo from './logo.svg'
import SessionTimeout from './SessionTimeout';
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
flexDirection: 'column',
minHeight: '100vh'
},
cardContainer: {
paddingBottom: 80,
paddingTop: 80,
},
}));
const LoginButton = (props) => {
return (
<Button
color="secondary"
data-testid="submit"
fullWidth
size="large"
onClick={props.onClick}
variant="contained"
>
Log In
</Button>
);
}
const LogoutButton = (props) => {
return (
<Button
color="secondary"
fullWidth
size="large"
onClick={props.onClick}
variant="contained"
>
Logout
</Button>
);
}
const App = () => {
const classes = useStyles();
const [isAuthenticated, setAuth] = useState(false);
let button;
const handleClick = () => {
setAuth(!isAuthenticated);
}
if (isAuthenticated) {
button = <LogoutButton onClick={handleClick}/>;
} else {
button = <LoginButton onClick={handleClick} />;
}
return (
<div className={classes.root}>
<Container
className={classes.cardContainer}
maxWidth="sm"
>
<SessionTimeout isAuthenticated={isAuthenticated} logOut={handleClick} />
<Box
mb={4}
display="flex"
justifyContent="center"
>
<img
alt="Logo"
src={logo}
/>
</Box>
<Box
mb={8}
display="flex"
justifyContent="center"
>
<Box mt={2}>
{button}
</Box>
</Box>
</Container>
</div>
);
}
export default App;

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.

react session timeout.gif

That's it :) Full code at - github.com/JamesUgbanu/react-session-timeout Thanks for reading and do not hesitate to ask any question if you have any.

No Comments Yet