tl;dr;
I’ve created mechanism that will leverage the secure nature of the browser sessionStorage or memoryStorage for authentication and will still allow the user to open multiple tabs without having to re-login every time.
A refresher about relevant browser storage mechanism
- localStorage ~5MB, saved for infinity or until the user manually deletes it.
- sessionStorage ~5MB, saved for the life of the current tab
- cookie ~4KB, can be saved up to infinity
session cookie ~4KB, deleted when the user closes the browser (not always deleted)
Safe session-token caching
When dealing with critical platforms it is expected that the session is ended when the user closes the tab.
In order to support that, one should never use cookies to store any sensitive data like authentication tokens. Even session-cookies will not suffice since it’ll continue to live after closing the tab and even after completely closing the browser.
(We should anyway consider to not use cookies since these have other problems that are need to be dealt with, i.e. CSRF.)
This leaves us with saving the token in the memory or in the sessionStorage. The benefit of the sessionStorage is that it’ll persist across different pages and browser refreshes. Hence the user may navigate to different pages and/or refresh the page and still remain logged-in.
Good. We save the token in the sessionStorage, send it as an header with every request to the server in order to authenticate the user. When the user closes the tab – it’s gone.
But what about multiple tabs?
It is pretty common even in single page application that the user will want to use multiple tabs. The afordmentioned security enahncment of saving the token in the sessionStorage will create some bad UX in the form of requesting the user to re-login with every tab he opens. Right, sessionStorage is not shared across tabs.
Share sessionStorage between tabs using localStorage events
The way I solved it is by using localStorage events.
When a user opens a new tab, we first ask any other tab that is opened if he already have the sessionStorage for us. If any other tab is opened it’ll send us the sessionStorage through localStorage event, we’ll duplicate that into the sessionStorage.
The sessionStorage data will not stay in the localStorage, not even for 1 millisecond as it being deleted in the same call. The data is shared through the event payload and not the localStorage itself.
Click to “Set the sessionStorage” than open multiple tabs to see the sessionStorage is shared.
Almost perfect
We now have what is probably the most secure way to cache session tokens in the browser and without compromising the multiple tabs user-experience. In this way when the user closes the tab he knows for sure that the session is gone. Or is it?!
Both Chrome and Firefox will revive the sessionStorage when the user selects “Reopen closed tab” and “Undo close tab” respectively.
Damn it!
Safari does it right and don’t restore the sessionStorage (tested only with these 3 browsers)
For the user the only way to be completely sure that the sessionStorage is really gone is to reopen the same website directly and without the “reopen closed tab” feature.
That until Chrome and Firefox will resolve this bug. (my hunch tells me that they will call it a “feature“)
Even with this bug, using the sessionStorage is still safer than session-cookie or any other alternative. If we’ll want to make it perfect we’ll need to implement the same mechanism using memory instead of sessionStorage. (onbeforeunload and alike can work too, but won’t be as reliable and will clear also on refresh. window.name is almost good , but it’s too old and has no cross-domain protection)
Sharing memoryStorage between tabs for secure multi-tab authentication
So… this will be the only real safe way to keep an authentication token in a browser session and will allow the user to open multiple tabs without having to re-login
Close the tab and the session is gone – for real this time.
The downsides is that when having only one tab, a browser refresh will force the user to re-login. Security comes with a price, obviously this is not recommended for any type of system.
Set the memoryStorage and open multiple tabs to see it shared between them. Close all related tabs and the token is gone forever (memoryStorage is just a javascript object)
*
P.S.* Needless to say that session management and expiration should be handled on the server side as well.