Skip to content

Logout user when inactive for a certain amount of time in a Typescript project

License

Notifications You must be signed in to change notification settings

polatengin/budapest

Repository files navigation

Netlify Status

GitHub Actions Status

Determine idle time in WepApps

You can use the running version of this project at https://polatengin-budapest.netlify.com/

What is idle timeout

Idle time is duration the user is remaining inactive on the web page. During idle time, user does nothing on the web page, he/she may even away from the computer.

Many web apps, such as banking, gaming, etc. need to detect if the user is idle to increase performance, security, etc.

For high risky web apps, 2-3 minutes inactivity is risky, such as, finance apps, personal password vault apps, etc.

For low risky web apps, sometimes 15-20 minutes inactivity is OK., such as, news apps, blog apps, etc.

Also, many web apps, need to have some calls to the backend or need to establish communication channels to backend, but when user is idle, it doesn't a requirement anymore. So, if the web app can detect the user is idle, then it can close communication channel and stop calling backend services to free-up resources on the backend side.

How to detect if the user is idle

When user is on the page, he/she usually use peripherals to interact with the page, such as, keyboard, mouse, touch screen, etc.

It's possible to attach couple of Events from DOM API and reset the timer if one of them triggered. If nothing happened in the past for example 20 seconds, we can conclude that the user is idle.

Here is the few events we can hook,

Implementation

Start by creating npm project with executing following command in your favorite Terminal (my favorite is Microsoft Terminal 😀)

npm init --force

It's possible to develop code in Typescript and transpile the code to Javascript with webpack. In order to prepare the project for that, let's add couple of DevDependencies;

npm install typescript webpack webpack-cli --save-dev

Also, it'll be needed to serve project locally for debug purposes, let's add http-server as a DevDependency;

npm install http-server --save-dev

Also, it'll be needed to pre-process html and typescript files with webpack, for example to minify them. Let's add couple of more DevDependencies;

npm install clean-webpack-plugin copy-webpack-plugin html-minifier-webpack-plugin html-webpack-plugin ts-loader --save-dev

Finally, it'll be needed to produce and emit events to notify the page that user is inactive for certain amount of time, let's add rxjs as a final dependency;

npm install rxjs

Now, we're ready to develop code.

Since we're good software engineers, we ❤ reusable code.

Let's create idle_timeout.src file in src folder.

First, we need a class definition;

import { Observable, Observer } from 'rxjs';

export class IdleTimeOut {
}

Now, we need a mechanism to prevent developers to instantiate the class more than 1 time. We're going to handle this requirement by implementing Singleton Design Pattern;

public static Current: IdleTimeOut = new IdleTimeOut();

private constructor() {
};

Now we need another mechanism to tap to few events;

['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'load'].forEach((event) => {
  document.addEventListener(event, this.Reset , true);
});

So, we can reset idle timer;

public Reset = () => {
  this._tick_count = 0;
  if (this._observer) {
    this._observer.next(this._tick_count);
  }

  clearInterval(this._interval);
  this._interval = setInterval(() => { this._observer.next(++this._tick_count); }, 1000);
}

Finally, we only need to have an Observable to alert outside-world about the progress of idle time;

private _tick_count: number = 0;
private _interval: ReturnType<typeof setInterval>;

private _observer: Observer<number>;

public OnTick: Observable<number> = new Observable();

this.OnTick = Observable.create((observer: Observer<number>) => { this._observer = observer });

That's it for the IdleTimeOut component, continue with creating index.html file under src folder with following content;

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Budapest - Detect if the user is idle</title>
</head>
<body>
  <span>Idle time: </span><span id="idle_time"></span>
</body>
</html>

Now, we can continue with creating index.ts file under src folder.

First of all, we need to import IdleTimeOut component;

import { IdleTimeOut } from './idle_timeout';

const $idle_time = document.getElementById('idle_time');

console.log(IdleTimeOut.Current);

We can call Reset() method and reset the idle timer programmatically;

IdleTimeOut.Current.Reset();

Also, we can attach to OnTick event and decide the actions, such as, when everything is fine, when to logout, etc.

IdleTimeOut.Current.OnTick.subscribe(seconds => {
  console.log(IdleTimeOut.Current);

  if (seconds <= 4) {
    $idle_time.innerText = 'everything is fine! 😀';
  } else if (seconds > 20) {
    document.location.href = '/logout';
  } else {
    $idle_time.innerText = `page has not been used for ${seconds} seconds`;
  }
});

Here is the example screenshot;

Sample Screenshot