Monday, August 3, 2015

Dividing Login from our Single Page Application

The Plan

One thing I have wanted to do with our single page application is to break it into three separate applications. The core reason is this. When you are at some part of the site and you hit reload or when you are logged in (cookie session wise) and go to a part of the application you have odd state. You have a logged in session, but your application does not have the basic state it needs to authenticate you, to figure out permissions, to figure out product and feature information.

My plan was to create a "Login" application, a "Public" application, and an application. The key would be that when you fetched the application page the server could fill in any authentication state. That way the application could always be certain the certain information was available and you would not have to have a bunch of asynchronous code that made sure you got information before you did something.

When you go to "login.html" it would check your login status. If you were logged in already it would redirect you to the application. Otherwise it would serve you "login.html". If you went to the "index.html" and you were logged in it would serve "index.html" with any needed information embedded in the page. Otherwise it would redirect you to "login.html".

There was also a potential speed advantage. The Login application would load much faster. It could then pre-load the application. This would hide load latency time by putting it in where the user is entering login information.

This seemed like a brilliant idea, in fact, I discovered later that Double Click, the Google advertising application was doing something similar. So I felt all good about myself, but then I ran into a problem...

The Problem

If a user follows a link into the site like https://blah.com/#page/id/foo, but then has to log in. What happens? Well, under the basic scheme I described above you lose the #page/id/foo part of the URL. It does not get sent to the server so the server just redirects you to https://blah.com/login.html and that page has no knowledge of the hash part of the URL.

History: Now you have access to the history, but you can't actually read it. You can just go to a page in the past. So you can do something like "go back two pages", but you can't check what those pages are.

Url Referrer: Another piece of information you have is "Url Referrer". This nice little piece of code tells you the last page you were at, but it doesn't contain the hash info.

Thoughts on Solutions

1. Using HTML5 History API

HTML5 has a superior History API. It can make a single page application look a lot like a series of pages. What happens is that when you navigate within the site instead of actually navigating it adds a URL onto the history and modifies its content. I haven't really considered this for three reasons. One is IE9 support. That might be going away soon, but it was still a consideration. Two, you need server logic to serve the application when the server gets a URL deep in the site. Three, it is a big change from what we are doing now and existing links would need special handling.

2. Using History combined with other info

When you log in, you normally would redirect to the application, but you could also use the history API to go back instead. You could have some kind of determining feature. This could be a server injected flag that would get injected into the login url when the core application redirected to login. This would expose the application to very odd behavior if someone went to the login page with that special url. You could mitigate this by cleaning the URL of this tag.

Another possibility is to check the "Url Referrer". You could see if you were referred to this page by the application page. Note that you could not use this to redirect to since it does not include the #, but you could use it to know that you just need to do history.back() or whether to redirect to your application. This might also work for returning you to the right place after a timeout.

3. Using a Shim

Another possibility is to use shims. Shims are tiny little JavaScript applications that are generally responsible for making some decisions and then loading your application. If instead of redirecting our application instead sent a shim we could have the shim store the hash in local storage and it could then redirect to the login page. The login page could check this known location and erase it and then redirect to it.

This could also handle the timeout contingency. When you time out you could write your current page into this location. Then login would put you back on the page you were in.

You could have some weird effects like if you timed out and left the application and then logged back in at another time you could go somewhere you didn't expect, but if we use session storage instead of local storage it might work better.

No comments:

Post a Comment