Detect inactive user and auto logout using javascript

Blog


author small image Siva Kishore G
Posted : 07 Oct 2022
Modified : 21 Mar 2023
Expert Developers

Introduction

Auto logout is a standard security feature implemented by organizations who crave higher security for their users. Banking applications, government websites, travel websites are top users of this feature. In this example, we will have different scenarios like multiple tabs opened and also in a different browser.

Lets see how to implement it using HTML,CSS & Javascript

User's Inactivity

User's inactivity is defined such as

  • Not focusing on the page / present in a different page
  • No mouse movement is observed
  • No keyboard entries

All the above actions are observed using Javascript functions and can trigger timeout when needed.

Logic of Auto Logout

We will create a JS function where all the above three actions are considered to determine if the user has expired the set timeout. Immediately, here we will think of a setTimeout function, which is not entirely wrong but it's the approach a newbie developer will take that can produce horrendous results.

Confused? Let me explain. The simple Javascript functions such as setTimeout and setInterval work fine but it's the issue that arises when the user navigates away from that page. The time elapsed will be considerably more than the code that's ticking on the actual page.

The second issue is, what about the different tabs? Different browsers? They all should log out at the same time whichever tab / page triggers the logout. Right?

  • setInterval & elapsed time

    Using set timeout and tracking the elapsed time, we can detect the user's inactivity. Refresh the elapsed time variable every time the user triggers with window focus and click on the webpage. This way, once the logout is triggered, the interval function is cleared and here is where we will force the user to logout.

    var elapsedTime = 0
    
    window.onfocus = function(){ elapsedTime = 0 }
    window.onclick = function(){ elapsedTime = 0 }
    
    var frequency = setInterval(function(){
      elapsedTime++
      if(elapsedTime > 3600){ // One hour timeout
        clearInterval(frequency)
        console.log("Logged out", elapsedTime)
      }
    },1000)
  • SetTimeout and tracker

    This type of timeout is designed such that it will only be triggered when the user navigates away to a different tab or a new browser

    var frequency = null
    var loggedout = false
    
    window.onblur = function(){ if(!loggedout)enableTimeout() }
    window.onfocus = function(){ if(frequency!==null){clearTimeout(frequency);frequency=null} }
    window.onclick = function(){ if(frequency!==null){clearTimeout(frequency);frequency=null} }
    
    function enableTimeout(){
      frequency = setTimeout(function(){
        loggedout = true
        console.log("User logged out")
      },(60*60*1000)) // 1 Hour timrout
    }
  • Using Web Workers (Recommended)

    As discussed above, web workers are excellent in offloading time based functions and communicating with the calling script. See the example below.

     // worker.js
    var frequency = null
    self.onmessage = function(msg){
      if(msg.data === 'enableTimeout'){
        enableTimeout()
      }else if(msg.data === 'disableTimeout'){
        if(frequency !== null) {
          console.log("Timeout disabled")
          clearTimeout(frequency)
          frequency = null
        }
      }
    }
    function enableTimeout(){
      console.log("Timeout enabled")
      frequency = setTimeout(function(){
        postMessage('logout')
      },60*60*1000) // 1 Hour timeout
    }
    
    // autologout.js
    var w = new Worker("/static_files/js/worker.js");
    w.onmessage = function(event){
      if(event.data === 'logout') {
        w.terminate()
        console.log("Proceed to logout")
      }
    }
    
    window.onblur = function(){ w.postMessage('enableTimeout') }
    window.onfocus = function(){ w.postMessage('disableTimeout') }
    window.onclick = function(){ w.postMessage('disableTimeout') }
    

Logout From every page / tab

We can achieve this in three ways

  1. Use socket.io to trigger the logout from the server. But again, one of the tabs from the user has to send the initial request to the server stating the timeout that has occurred. Then using the web socket, we can trigger logouts on every page

    The below code uses an array (users) to track the users but in general you would need to save the users status in a database. Lets not get into how to save the users and which database to use since its out of scope of this article.

    var express = require('express');
    var app = express();
    const http = require('http');
    const server = http.createServer(app);
    const io = new Server(server);
    
    var users = {}
    io.on('connection',client=>{
      client.on("newUser",userid=>{
        if(!users[userid]) users[userid] = []
        users[userid].push(client.id)
      })
      client.on("disconnect",userid=>{
        users[userid] = users[userid].filter(u => u!==client.id)
      })
      client.on("logout",userid=>{
        var pageUsers = users[userid]
        for(var p of pageUsers){
          client.to(p).emit("doLogout","")
        }
      })
    })
    
    server.listen(9000)
    var socket = io("https://chat-website.com");
    
    socket.on("connect", () => {
      var random = Math.random().toString(36).substr(2) // Random String
      if(localStorage.getItem("autologout") === null) localStorage.setItem("autologout",random)
      else random = localStorage.getItem("autologout")
      socket.emit("newUser", random)
    })
    
    socket.on("doLogout",e => console.log("Do logout here") )
  2. Using localStorage. Once the local storage value is modified, all the opened tabs will share the same value, in other words the localStorage will be in sync with all the opened tabs. Then use the JS timing function (setInterval) to check the user's activity status periodically and call the logout route. See the code below to get an idea.
  3. setInterval( function(){
      if(userActive) localStorage.setItem('userActive', 1)
      else {
        localStorage.removeItem('userActive')
        window.location.replace('/logout')
      }
    }, 10000 ) 
  4. Invalidate the token. It's a common practice now-a-days that a token is sent with every request made from the user which is generally a JSON Web token. So, once the user triggers the logout, send a request to the server to invalidate the token. This way, all the other tabs are virtually logged out since the token is no longer valid.

HTTP is stateless

HTTP is stateless! which means, the user has to trigger the auto logout and hence it's tempting to implement this auto logout feature entirely in the front end in a javascript file. But, for a veteran hacker, he/she can simply override the JS function using the developer console and can stop the page from logging out ever. Not a desirable result. Ain't it?

How to overcome them? Well, there is no fool-proof way of stopping any code manipulation attempt, but we can make it hard to override the JS code by obfuscating the script. But sadly, there are also de-obfuscators available online.



Post a comment

I promise, I keep it clean *

Comments

Alert SVG Cookie Consent

This website uses cookies and similar technologies, to enhance your browsing experience and provide personalized recommendations. By continuing to use our website, you agree to our Privacy policy.