How to differ sessions in browser-tabs?

265,596

Solution 1

You can use HTML5 SessionStorage (window.sessionStorage). You will generate a random id and save in session Storage per Browser Tab. Then each browser tab has his own Id.

Data stored using sessionStorage do not persist across browser tabs, even if two tabs both contain webpages from the same domain origin. In other words, data inside sessionStorage is confined to not just the domain and directory of the invoking page, but the browser tab in which the page is contained in. Contrast that to session cookies, which do persist data from tab to tab.

Solution 2

You have to realize that server-side sessions are an artificial add-on to HTTP. Since HTTP is stateless, the server needs to somehow recognize that a request belongs to a particular user it knows and has a session for. There are 2 ways to do this:

  • Cookies. The cleaner and more popular method, but it means that all browser tabs and windows by one user share the session - IMO this is in fact desirable, and I would be very annoyed at a site that made me login for each new tab, since I use tabs very intensively
  • URL rewriting. Any URL on the site has a session ID appended to it. This is more work (you have to do something everywhere you have a site-internal link), but makes it possible to have separate sessions in different tabs, though tabs opened through link will still share the session. It also means the user always has to log in when he comes to your site.

What are you trying to do anyway? Why would you want tabs to have separate sessions? Maybe there's a way to achieve your goal without using sessions at all?

Edit: For testing, other solutions can be found (such as running several browser instances on separate VMs). If one user needs to act in different roles at the same time, then the "role" concept should be handled in the app so that one login can have several roles. You'll have to decide whether this, using URL rewriting, or just living with the current situation is more acceptable, because it's simply not possible to handle browser tabs separately with cookie-based sessions.

Solution 3

The window.name Javascript property, is the only thing that will persist across tab activity, but can remain independent (instead of URL guff).

Solution 4

You shouldn't. If you want to do such a thing either you need to force user to use a single instance of your application by writing URLs on the fly use a sessionID alike (not sessionid it won't work) id and pass it in every URL.

I don't know why you need it but unless you need make a totally unusable application don't do it.

Solution 5

I've come up with a new solution, which has a tiny bit of overhead, but seems to be working so far as a prototype. One assumption is that you're in an honour system environment for logging in, although this could be adapted by rerequesting a password whenever you switch tabs.

Use localStorage (or equivalent) and the HTML5 storage event to detect when a new browser tab has switched which user is active. When that happens, create a ghost overlay with a message saying you can't use the current window (or otherwise disable the window temporarily, you might not want it to be this conspicuous.) When the window regains focus, send an AJAX request logging the user back in.

One caveat to this approach: you can't have any normal AJAX calls (i.e., ones that depend on your session) happen in a window that doesn't have the focus (e.g. if you had a call happening after a delay), unless you manually make an AJAX re-login call before that. So really all you need do is have your AJAX function check first to make sure localStorage.currently_logged_in_user_id === window.yourAppNameSpace.user_id, and if not, log in first via AJAX.

Another is race conditions: if you can switch windows fast enough to confuse it, you may end up with a relogin1->relogin2->ajax1->ajax2 sequence, with ajax1 being made under the wrong session. Work around this by pushing login AJAX requests onto an array, and then onstorage and before issuing a new login request, abort all current requests.

The last gotcha to look out for is window refreshes. If someone refreshes the window while you've got an AJAX login request active but not completed, it'll be refreshed in the name of the wrong person. In this case you can use the nonstandard beforeunload event to warn the user about the potential mixup and ask them to click Cancel, meanwhile reissuing an AJAX login request. Then the only way they can botch it is by clicking OK before the request completes (or by accidentally hitting enter/spacebar, because OK is--unfortunately for this case--the default.) There are other ways to handle this case, like detecting F5 and Ctrl+R/Alt+R presses, which will work in most cases but could be thwarted by user keyboard shortcut reconfiguration or alternative OS use. However, this is a bit of an edge case in reality, and the worst case scenarios are never that bad: in an honour system configuration, you'd be logged in as the wrong person (but you can make it obvious that this is the case by personalizing pages with colours, styles, prominently displayed names, etc.); in a password configuration, the onus is on the last person who entered their password to have logged out or shared their session, or if this person is actually the current user, then there's no breach.

But in the end you have a one-user-per-tab application that (hopefully) just acts as it should, without having to necessarily set up profiles, use IE, or rewrite URLs. Make sure you make it obvious in each tab who is logged into that particular tab, though...

Share:
265,596
Oriol Terradas
Author by

Oriol Terradas

SOreadytohelp

Updated on December 03, 2021

Comments

  • Oriol Terradas
    Oriol Terradas over 2 years

    In a web-application implemented in java using JSP and Servlets; if I store information in the user session, this information is shared from all the tabs from the same browser. How to differ sessions in the browser-tabs? In this example:

    <%@page language="java"%>
    <%
    String user = request.getParameter("user");
    user = (user == null ? (String)session.getAttribute("SESSIONS_USER") : user);
    session.setAttribute("SESSIONS_USER",user);
    %>
    <html><head></head><body>
    <%=user %>
    <form method="post">
    User:<input name="user" value="">
    <input type="submit" value="send">
    </form>
    </body></html>
    

    Copy this code in a jsp page (testpage.jsp), deploy this file in an existing context of a web application on the server (I use Apache Tomcat), then open a browser (FF, IE7 or Opera) using the correct URL (localhost/context1/testpage.jsp), type your name in the input and submit the form. Then open a new tab in the same browser, and then you can see your name (get from the session) on the new tab. Be careful with the browser-cache, sometimes seems that it doesn't happen, but it's in the cache, refresh the second tab.

    Thanks.

  • Oriol Terradas
    Oriol Terradas over 15 years
    I think rewriting links to encode sessions is a tedious and error-prone. I have a big application, with a lot of links, I need a transparent solution or easy to implement.
  • Oriol Terradas
    Oriol Terradas over 15 years
    It's for a big application that keeps the user information and the envirnoment. When somebody login with differents users in differents tabs, for test or for differents roles, then he's crossing information from tabs.
  • Djonatas Tenfen
    Djonatas Tenfen over 15 years
    I see as I say this is bad idea. I assume this app will be for a team or something like that, not public to everyone. In that case I'd say running a new Internet Explorer or running a new profile on Firefox can save the day. Other solutions will bite you in the arse for the rest of the project-IMHO.
  • Djonatas Tenfen
    Djonatas Tenfen over 15 years
    Running a new IE as in executing IE again as a new window. This will separate sessions.
  • Oriol Terradas
    Oriol Terradas over 15 years
    It's for a big application that keeps the user information and the envirnoment. When somebody login with differents users in differents tabs, for test or for differents roles, then he's crossing information from tabs.
  • Adam Bellaire
    Adam Bellaire over 15 years
    I guess this got downvoted for saying "this is a bad idea", but his answer is correct. Unless you want to pass data through GET or POST with every request, you can't do this. Sessions alone don't cut it, as pretty much every other answer has pointed out.
  • Djonatas Tenfen
    Djonatas Tenfen over 15 years
    Adam, as you see it's not easy to be honest :)
  • Peter
    Peter almost 14 years
    +1 because you took the time to really think this through! :-) Looking at all the caveats you just know it's a bad idea. My lessons learned from this stuff is to truly understand what data should go into sessions and which data shouldn't.
  • George
    George over 11 years
    old answer I know, but google mail allows you to have different accounts per tab and it's not a "totally unusable application"
  • felickz
    felickz about 11 years
    window.sessionStorage does as well
  • felickz
    felickz about 11 years
    careful as session storage gets copied into a new tab when the user chooses "open in new tab" ... wish i had link for details but see: bugzilla.mozilla.org/show_bug.cgi?id=818389
  • nakib
    nakib almost 11 years
    Be aware that the thing you save in the window.name setting will still be available in other domains, when the user changes to other pages in the same tab.
  • jswanson
    jswanson over 10 years
    From docs: "Data stored using sessionStorage do not persist across browser tabs, even if two tabs both contain webpages from the same domain origin. In other words, data inside sessionStorage is confined to not just the domain and directory of the invoking page, but the browser tab in which the page is contained in. Contrast that to session cookies, which do persist data from tab to tab." Simple testing confirms this behavior in Chrome and FF.
  • Jeff Marino
    Jeff Marino almost 10 years
    I really like your simplified answer and Occam's razor reference. Just wanted to double check that this solution is still working for you.
  • Gili
    Gili almost 10 years
    This is probably okay, but is theoretically unsafe. Some operating systems (e.g. Windows) have a very coarse timestamp granularity which means you might look up the timestamp multiple times and get back the same value. Furthermore, if you reopen a browser after a crash and it reopens all tabs at once they might get the same timestamp.
  • rosenfeld
    rosenfeld over 9 years
    It worths noticing that if refreshing the page should keep its session this approach would not work. The other suggested approach in another answer of using window.sessionStorage seems more reasonable to me.
  • Mhmd
    Mhmd over 9 years
    @George, The answer still right, and for your example you will see in the url number represent the index of accounts stored in cookies, google mail is just storing all cookies and select one according to the url.
  • George
    George over 9 years
    Not sure the answer is still right, you clearly can do it. Gmail does it. As for how it does it, it may not be elegant but it works and that's what's important
  • Mike A.
    Mike A. almost 9 years
    @quijibo Still works perfectly in my application, yes. As for refreshing the page, may be true for some browsers, using the window.sessionStorage may solve the issue, haven't tried it
  • JosiahDaniels
    JosiahDaniels over 8 years
    Note, the ID will be duplicated when using Chrome's "Duplicate Tab" feature. This generally isn't a problem, but should be thought through.
  • André Miranda
    André Miranda almost 8 years
    What is the function "se_appframe()"?
  • Ron Burk
    Ron Burk over 7 years
    This seems like a clever alternative to URL-rewriting. You end up with desired variable (session ID) in an HTTP-conformant place that's visible but not obtrusive. Nits that spring to mind: 1) need wildcard on DNS, obviously, 2) your entire website must avoid any absolute URLs that would route the user back to (e.g.) the "www" subdomain, 3) probably want to keep web crawlers out, but this is probably a private-web situation so that may be done already. Thanks for sharing this!
  • serdar.sanri
    serdar.sanri almost 7 years
    I don't agree on totally unusable application part. Lets say you have a login then looking at different accounts in your application. You don't want to pass an account id parameter each time you do something on each account. So you store currently selected account in session to get it back when you need it. Then also you may open different tabs to look different accounts at the same time. In that case, you have the latest account ID in session, but if you go back another previous tab, the account you see on browser is not same as what server has.
  • Tiago Freitas Leal
    Tiago Freitas Leal almost 6 years
    Except when you "Duplicate" a tab in Chrome or Firefox. In this case, SessionStorage is copied.
  • Oliver Williams
    Oliver Williams over 5 years
    Just a very late add-on, as to why: because I need to know this in order to know WHICH page on my site, for example, a user is focused on, and not just that they've gone from page to page (instead they went from tab to tab).
  • Stefan Steiger
    Stefan Steiger about 5 years
    @Gonzalo Gallotti: And how will that help me if the session is server-side ? )))
  • Gonzalo Gallotti
    Gonzalo Gallotti about 5 years
    @StefanSteiger. Then you can send the BrowserTab id (saved in Session Storage) with your Ajax Call. In the server side you will need custom logic, because the WebSession is the Same. But you can create a HashMap with Session objects by tab.
  • Stefan Steiger
    Stefan Steiger about 5 years
    @Gonzalo Gallotti: And where is your ajax call an a form-post (aka postback) ? Besides, I know that. My point is, if you do that, you'll have to make massive changes to each and every byte of code that uses a session. Hundreds of pages, potentially thousands of files. Perhaps libaries that are used in other projects, too. You're not gonna do that, ever. Even though, for a very small project, it's an option. However, if the project were that small, I'd rather completely remove the reliance on any session object, as that is usually an antipattern. (aka a very very very bad thing to do)
  • Stefan Steiger
    Stefan Steiger about 5 years
    @Gonzalo Gallotti: Using multiple subdomains with a wildcard-dns-entry is most likely a much better alternative, as that requires changing only the login/SAML code. stackoverflow.com/a/23075956/155077
  • Stefan Steiger
    Stefan Steiger about 5 years
    @user3534653: I like the approach. But you said "no programming involved". Then you go on to say "with little code change". So really, a little code change is not programming ? ;) Also, this approach might not work if you have multiple applications with canonical links where the domain is hard-coded/configured (canonically).
  • Bruno Francisco
    Bruno Francisco about 5 years
    Old answer but I may add that Whatsapp and Telegram don't allow you to have two tabs open at the same time. This doesn't make them unusable
  • Kiquenet
    Kiquenet over 4 years
    What is se_appframe ?
  • PerryCS
    PerryCS about 3 years
    You may already have thought of this but... what is to stop someone from guessing the subdomain. I hope there is more to it than just a random subdomain. Would take a few seconds to find all the subdomains that are active, and then view the page (unless there was other code to keep that from happening). Isn't that kinda like session "hijacking" but in this case it would be subdomain "hacking". :) I'm sure you have more code to protect that... can't rely on anonymity for security.
  • Mike A.
    Mike A. about 2 years
    se_appframe() is a function i have that walks up the framework (iframes, parents and such) and finds the topmost frame for my applicaiton. It's an old beast that has framesets. We're re-writing the beast to an SPA, but for now, we're stuck in framesets. in most cases you're just looking for somethign like window.topmost