How to differ sessions in browser-tabs?
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...
Comments
-
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 over 15 yearsI 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 over 15 yearsIt'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 over 15 yearsI 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 over 15 yearsRunning a new IE as in executing IE again as a new window. This will separate sessions.
-
Oriol Terradas over 15 yearsIt'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 over 15 yearsI 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 over 15 yearsAdam, as you see it's not easy to be honest :)
-
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 over 11 yearsold answer I know, but google mail allows you to have different accounts per tab and it's not a "totally unusable application"
-
felickz about 11 yearswindow.sessionStorage does as well
-
felickz about 11 yearscareful 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 almost 11 yearsBe 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 over 10 yearsFrom 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 almost 10 yearsI really like your simplified answer and Occam's razor reference. Just wanted to double check that this solution is still working for you.
-
Gili almost 10 yearsThis 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 over 9 yearsIt 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 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 over 9 yearsNot 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. 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 over 8 yearsNote, 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 almost 8 yearsWhat is the function "se_appframe()"?
-
Ron Burk over 7 yearsThis 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 almost 7 yearsI 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 almost 6 yearsExcept when you "Duplicate" a tab in Chrome or Firefox. In this case, SessionStorage is copied.
-
Oliver Williams over 5 yearsJust 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 about 5 years@Gonzalo Gallotti: And how will that help me if the session is server-side ? )))
-
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 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 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 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 about 5 yearsOld 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 over 4 yearsWhat is se_appframe ?
-
PerryCS about 3 yearsYou 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. about 2 yearsse_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