Binding tab-specific data to an HTTP GET request Binding tab-specific data to an HTTP GET request ajax ajax

Binding tab-specific data to an HTTP GET request


Okay, after going through many different iterations, here is the implementation we ended up with:

Variables

  • There are two kind of data stores:
  • We store the following variables:
    • IndexedDB contains publicToken, nextTabId.
    • sessionStorage contains privateToken, tabId.

publicToken, privateToken

  • See https://stackoverflow.com/a/1592572/14731 for a definition of an authentication token.
  • There are two kinds of authentication tokens: public and private.
  • publicToken is the token returned by the last login operation, across all tabs.
  • privateToken is the token returned by the last login operation of the current tab.

tabId

  • Each tab is uniquely identified by a token called tabId.
  • nextTabId is a number that is accessible across all tabs.
  • If a tab does not have an id, it creates a new one based on nextTabId and increments its value.
  • For example, tabId could have a value of "com.company.TabX" where X is the number returned by nextTabId.

Login/Logout

  • Every time a tab logs in, privateToken and publicToken are overwritten using the authentication token returned by the server.
  • When a user logs out, we delete privateToken and publicToken on the browser side, and privateToken on the server side. We do not delete publicToken on the server side.
  • This means that anytime a tab logs out, all all tabs sharing the same privateToken will get logged out as well. Any tabs using a different token will be unaffected.
  • When do multiple tabs share the same privateToken? When you open a link in a new window or tab, it inherits the privateToken of the parent tab.
  • If we were to delete publicToken on the server, a tab logging out with privateToken X, publicToken Y would cause tabs with privateToken Y to get logged out (which is undesirable).

On page load

  • Scan the page for HTML links.
  • For each link, append a tabId query parameter to the URL. The parameter value is equal to the value of tabId.
  • Strip the tabId URL parameter from the current page using history.replaceState() so users can share links with their friends (tabId is user-specific and cannot be shared).
  • Delete the tabId cookie (more on this below).

When a link is clicked

  • The tab creates a tabId cookie and follows the link.
  • The cookie has a name equal to the value of tabId and a value equal to the value of privateToken

When a server receives a request

  • If the tabId parameter is missing, then redirect the browser to GetTabId.html?referer=X where X is the current URL.
  • If tabId is present but the authentication token is invalid or expired, then redirect the browser to the login screen.

GetTabId.html

  • If the tab does not have a privateToken, copy publicToken into privateToken.
  • If both privateToken and publicToken are undefined, redirect to the login page.
  • The page takes a URL parameter called referer which indicates where to redirect to on success.
  • If the tab has a privateToken, append the tabId parameter to the referer page and redirect back to it.
  • Use window.location.replace() when redirecting to remove GetTabId.html from the browser history.

Why do we keep on deleting/adding cookies?

  • We try to minimize the number of cookies sent to the server on each request.
  • If we did not delete the tabId cookie on page load, then each time a tab would make a request all of the other tabs' cookies would get sent as well.

Known issues

  • "View Source" opens the URL missing tabId. As result, it gets the source-code of the page which redirects to GetTabId.html instead of the actual page.
  • Awkwardly long page reloads (client is redirected to GetTabId.html and back to the original page).

Apologies for the long implementation details, but I could not find an easier/shorter solution.