If you ever have developed secure web applications that make use of AJAX, you have most likely been confrontend with situations where an AJAX request occurs after the session has timed out. Where the server is supposed to return some HTML of JSON, you get a ’401 Unauthorized’ or an empty response depending on how you have it implemented. The question is then how to deal with that kind of responses. You could read the headers of the response and redirect when a 401 status is detected, but I can’t tell for sure that there isn’t/won’t be a browser that will catch those errors and handle it in a way that messes up the user experience. Also, you don’t want to check explicitly for such error after every AJAX request.

So the solution I implemented is explained below. I will show you how it can be done with Symfony and jQuery, but it should be straightforward to achieve the same with other frameworks (like with a Zend Framework Front Controller Plugin for example). What really matters is the idea behind the solution.

Server side:

class frontendConfiguration extends sfApplicationConfiguration
{
  	public function configure()
  	{
  		// add event listener
  		$this->dispatcher->connect('context.load_factories', array(
      			$this, 'isAuthenticatedAjaxRequest'
    		));
  	}

  	/**
  	 * This method checks if an Ajax request comes in and
  	 * if the session has not expired.
  	 * If so, a custom header is returned (a standard 401
  	 * might get trapped and handled by the browser)
  	 * and a javascript "ajaxSuccess" listener will detect this
  	 * header and redirect to the webroot.
  	 *
  	 * @param sfEvent $event
  	 */
  	public function isAuthenticatedAjaxRequest(sfEvent $event)
  	{
  		$context = $event->getSubject();
  		$request = $context->getRequest();
  		if($request->isXmlHttpRequest()) {
  			$user = $context->getUser();
  			if($user->isAuthenticated() === false) {
  				header('NOT_AUTHORIZED: 499');
 				exit();
  			}
  		}
  	}
}

So this is what we do here:
Before the request is being dispatched, we perform an additional check on the request. One way to implement this in Symfony is to connect a method to a certain event, in this case the “context.load_factories” event. The reason why we wait until the factories are loaded is because we will need the session data, which depends on the Storage factory.
In the triggered method, we check if concerns an AJAX request. If that’s the case, we verify if the user is authenticated and if not, we return a custom header ‘NOT_AUTHORIZED’ with status number 499. By using a custom header, we can be sure it will not be trapped by the browser.

Client side:

I will be using jQuery here basically because it’s my favorite Javascript framework.

$(function() {
	$('body').bind(
		'ajaxSuccess', 
		function(event, request, settings) {
		if (request.getResponseHeader('NOT_AUTHORIZED') === '499') {
   			window.location = '/';
		};
	});
});

In jQuery, by binding to the “ajaxSuccess” event, we can make sure that every AJAX response will trigger our function. All this function does is check if our custom header is set and if not, redirect the browser to the webroot. That would be a regular browser request which can be dealt with like any other normal request.

If you would have any remarks or feedback on how to further improve this, I’ll be happy to hear it from you.