So you’re building a web app that lets users to create their own accounts. And for one reason or another, you want to log them out of their accounts when they close the browser tab or window—but not when they refresh it.
What’s the best way to accomplish this?
Right off the bat, you need to know that there is no direct way to do this. In JavaScript, there is no event that is fired when the user closes the tab or window on the client side. However, there are indirect ways to infer this, and I will walk you through them in this post.
With Session Storage
When the user opens a new browser tab or window, a new session starts. That session lasts for as long as the tab or window is open, and persists across refreshes and restores.
As a developer of a web app, you can use a Web API to store, retrieve, and manipulate data on a session level, for as long as that session is active. You can do this via the Window.sessionStorage()
interface.
The sessionStorage
data is stored in key/value pairs and is specific to the protocol of the page. This is important to know because the sessionStorage
objects for mysite.com accessed through HTTP (http://mysite.com/), will not be the same as those for mysite.com accessed through HTTPS (https://mysite.com/).
The three basic methods for working with sessionStorage data are:
// Set item in sessionStorage
sessionStorage.setItem('key', 'value');
// Get the value of an item from sessionStorage
let item = sessionStorage.getItem('key');
// Erase an item from sessionStorage
sessionStorage.removeItem('key', 'value');
Now that you know all the above, let’s talk about the simplest possible implementation for logging a user out when they close the browser tab or window.
How It Works
Step 1. When the user logs in, save a key/value pair in sessionStorage
to record the fact as a boolean (where “true” stands for logged in and “false” for logged out).
// Set isLoggedIn : true in sessionStorage on login
sessionStorage.setItem('isLoggedIn', 'true');
Step 2. When the user logs out, update the key/value pair in sessionStorage accordingly:
// Set isLoggedIn : false in sessionStorage on logout
sessionStorage.setItem('isLoggedIn', 'false');
Step 3. In your web app’s JavaScript code, implement logic that gets the value of the isLoggedIn
item and stores it in a variable:
// Get value of isLoggedIn and store in checkUserSession variable
let checkUserSession = sessionStorage.getItem('isLoggedIn');
Step 4. Use the value of isLoggedIn
to build the rest of the logic in your app:
- When
isLoggedIn
is true, the user is logged in, and the browser tab or window is opened. - When
isLoggedIn
is false, the user is logged out, and the browser tab or window is opened. - When
isLoggedIn
is null, the user hasn’t logged in yet, and/or has reopened the page after closing the tab or window.
In this implementation scenario, the isLoggedIn
variable being null is what helps us infer that the user is coming into the web app with a new session.
For security reasons, you will probably want to encode the data in a JSON Web Token and add some sort of session validation logic that relies on more than just a boolean.
Drawbacks
We can’t distinguish between new and existing users:
We don’t really know if they’re using the app for the first time, or if they’ve used the app before, then closed the tab or window and come back again. And, in nine times out of ten, we won’t need to.
If it’s important to distinguish between new and returning users before they’ve logged in, you could save a first-party cookie or key/value pair with a timestamp for the user’s last visit.
New tabs are new sessions with separate sessionStorage objects:
This method has one drawback. If the user opens the app from a new tab in the same browser window, they will also open a separate session. So they will be logged in in one tab and logged out in the other.
Once again, you could counteract this drawback by saving a first-party cookie or another key/value pair in localStorage
, both of which can be accessed across tabs. Then pairing them with a function that clears the cookie or key/value pair when isLoggedIn
is false or null.
With a Keep Alive Function
How It Works
The setInterval(function(){}, duration)
method, as documented on MDN Web Docs, lets you execute a JavaScript function every delay
milliseconds.
You could use it to create a keep alive function that pings the server from the client at a strict interval:
setInterval(function() {
// Your keep alive code goes here
}, duration);
If the server, counted from the last keep-alive ping, is not pinged by the client for a certain amount of time, the session is invalidated on the server side and the client is logged out the next time they open your web application.
You will probably need to store a value or two in a first-party cookie, sessionStorage
, or localStorage
for this to work. And you will need to build up a good deal of logic on the server side.
Drawbacks
It consumes resources and bandwidth:
When a function runs every X milliseconds, it consumes resources from the client. To ping a server, whether through a keep-alive call (forbidden in HTTP/2) or by loading a pixel, it also consumes network bandwidth.
It’s network-dependent:
If your user loses Internet connectivity for a long enough time, they will also lose their session. This can be highly frustrating if your users are accessing the app while commuting or traveling.
It takes time to log the user out:
With this method, it will take a given amount of time to log a user out after they’ve closed the tab or browser. This may or may not be an issue, but it is a drawback to keep in mind.
In Conclusion
For better or worse, there isn’t a way to directly know from the client when the tab or window was closed, at least not in JavaScript. However, there are ways to infer it with a high enough level of confidence—and you now know two of them.