AngularJS in WARs – The Case of the Session Timeout

Artikel in deutsch ⤴︎

AngularJS is a great framework to build modern web applications. Java EE offers a rich and powerful environment to build reliable, scalable, and secure server applications. The combination of both worlds is straight forward: The web archive (WAR) contains all the HTML pages and the JavaScript code. The access to the server is done using JAX-RS.

Also the access control can be implemented using the standard Java EE tools. Using form-based authentication, a user first has to enter login and password before he can access the web pages. In addition to the web pages the servlet used by the AngularJS application can be secured in the same way.

That should solve all problems, am I right? Almost. What is not covered by default is the handling of session timeouts. When a session times out the user is redirected to the login page to establish a new session. This is fine for a human user. An AngularJS application can get quite confused. It access the server in the background, expects a JSON response, and receives instead an HTML page. Here, we show a solution for this problem.

This solution is described in detail in our book. If you like to read (and buy) it, here is the link:
https://itunes.apple.com/de/book/rich-web-apps-mit-angularjs/id847457516

The example code of our solution is on GitHub:
https://github.com/akquinet/dailyplanner-angularjs

The idea is to check at every server request if the session is still valid. If it is not valid anymore, the browser is redirected to the login page. Because it is quite laborious to implement this for every server request again, we register an interceptor, named httpInterceptor, at the $httpProvider. This is done in the configuration phase of the application:

.config([
    "$httpProvider",
    function ($httpProvider) {
        $httpProvider
            .interceptors.push("httpInterceptor");
    }
]);

The next task is to recognize that a session got invalid. In this case the server is sending the login page as response. To distinguish the login page from other HTML pages, we added a meta information into the HTML-head of the page:

  <meta name="unauthorized" content="true">

Our interceptor now checks for every response if it is an HTML-page. If this is true, it looks for our added meta information. If it is found, the browser is redirected to the login page and the request itself is rejected, to allow the application to react on the error. This is the code:

.factory("httpInterceptor", ["$q", "$window", "$log",
  function ($q, $window, $log) {
    return {
     "response": function (response) {
        var responseHeaders;
        responseHeaders = response.headers();
        if (   responseHeaders["content-type"]
                 .indexOf("text/html") !== -1
               && response.data
               && response.data
                   .indexOf('<meta name="unauthorized" content="true">') 
                      !== -1) {
          $window.location.reload();
          return $q.reject(response);
        }
        return response;
      }
    };
 }
])

This solution works reliable. But it has two shortcomings:

  • You have to ensure that the login page, and only the login page, always contains the correct meta information. We added some comments to the HTML-code to help developers remembering.
  • Every HTML-response is scanned for the meta information. In our applications, this is not a problem, because the server usually sends JSON responses. But for an application with a lot of HTML responses the additional scans can create a significant overhead.

Of course, if you know of a better solution, we would appreciate to hear about it.

🙂

3 thoughts on “AngularJS in WARs – The Case of the Session Timeout

  1. Yes, your solution of using a specific return code would be much cleaner. It would be even more REST-like if the servlet for the server call is not connected to a session at all. Instead it would authenticate against another service and receive some kind of token. This project is going in this direction:
    http://keycloak.jboss.org
    At lot of others surely do too.

    But, with form-based authentication the container intercepts the requests and redirects it to the login page without sending an error. A user would be pretty surprised to see a HTTP-error….

    The charm of our approach is that it just needs about 10 lines of well known configuration and the code above to get it to work. The container takes care of authentication and authorization and neither the server nor the client logic has to be adapted.

  2. Why not simply use an appropriate http response code to signal a missing authentication? No need to parse returned HTML then. The meta tag smells a lot like a hack. A 401 (or maybe a 403) response from the server sounds like a lot more straight forward solution. You can still intercept that like you do now and redirect to the login if appropriate.

Comments are closed.