Tuesday, February 3, 2015

Single Page Application or Double Page Application: A Solution to Login Problems

I work on a project and I have wrestled with the following issue. The whole application is a single page (SPA) and authentication is done by an OAuth server and is handled in cookies. The login flow that is part of the SPA logs you in. Part of this login process is acquiring your user permissions. Note that whether you are logged in or not is controlled by a cookie, but what you can do is controlled by a XHR request.

So the basic flow is simple. You login and when you are logged in you do a request for permissions. Once you have permissions you direct users to the right page. But what happens when you reload or are already logged in a follow some bookmark. You do not go through the login process because you already have a valid cookie. But you don't have permissions data. So you need to make sure to get it. Okay, so one way to do this would be at the start of the Angular application get credentials and don't really do anything until you have them. Sadly, Angular doesn't really let you do this. 1) You could create a little JQuery request that gets the data before launching Angular. 2) You could add a router "resolve" function that will get the needed data before routing to a page.

We ended up doing #2. Mainly because #1 was very ugly. Making your server calls using completely different code patterns did not sit well with the team.

So I always like to think about what the right way to do something as I often barrel down the wrong path for reasons of expediency. I believe the right way to do things is to use the server more. Now I have noticed a trend in SPA developers that they like to do everything on the client, including stuff that should be done on the server. Now here is what I think the best solution is.

Divide your single page application into two single page application, login flow and operations flow. Login flow can include all the pages that do not require any login like forgot password pages and, of course, login. Once you are logged in you redirect to a new "operations.html" page. This page is an active server page that starts a SPA. It dynamically has JavaScript objects added that have your permissions information. Then your Angular application can have a service thats knows the location of these permissions and you basically are guaranteed to have them whenever you do a request for the "operations.html" part of your application.

Now "unobtrusive JavaScript" would say that this is horrible because you are putting JavaScript objects on a page and not serving them via XHR. Well, Angular itself is a pretty significant rejection of "unobtrusive JavaScript" as are SPAs themselves. Now I remember working on code that had JavaScript and CSS and server code all mixed together into an unreadable pile of goo. I know the value of separating out your client code. In fact, I think it is one of the strongest reasons to pursue a SPA approach. That said, we should avoid devotion to "unobtrusive JavaScript" and instead figure you clear mechanisms that work. Including a server based JavaScript object is a clear, simple approach that I have used well in the past.

Another potential benefit to this approach is pre-loading your cache. You can delay the loading of script files until after the page is up and running. This means that your loading page can quickly get up and running and then while you are typing information in or hitting a button the page can be loading pieces of your application in the background. You shouldn't have to wait for your operational code to load in order to be able to login. Of course, this doesn't help when you are already logged in, but in that case hopefully your stuff is already in cache.

No comments:

Post a Comment