POST a request after session timeout

When creating a web application that requires user authentication, it is necessary to validate the user on every GET or POST request to the server. But if the logged-in session is no longer valid when the user submits the request, then the application needs to re-authenticate the user. This process usually entails a new request to sign-in to the application, and a subsequent loss of the initial POST payload, as shown below:

Session Timeout Before

In this article, we discuss a possible technique for dealing with this often frustrating usability issue. Our answer consists of using Javascript to temporarily halt the form submission, and instead issue a background, asynchronous request (AJAX) to the server in order to check for the validity of the session. If still active, continue with form submission; otherwise, open a pop-up window to re-authenticate the user.

Session Timeout After

Background setup#

For the purposes of this discussion, consider a simple, generic web application for which the user needs to authenticate. Suppose, further, that the authentication is a typical username and password combination entered on a dedicated login form. For security reasons, all sessions expire after some time. Because sessions may be removed for reasons other than a predictable expiration, we seek a proactive method by which the browser may detect it is using a no-longer valid session prior to submitting a particular POST request.

Why POST requests#

We focus on POST requests because those are the ones most succeptible to data loss. Indeed, in a GET request, the URL contains all the parameter-value pairs. In this case, the returned HTML could be the dedicated login form. Furthermore, upon re-authentication, the server can redirect the user to the original request.

Using HTTP status codes in login form#

Most implementations of the simple username/password authentication form discussed above do not use HTTP status codes in their response. For completeness, we advocate a return value of 403 alongside the login form when the user makes a request for which they need to log in. It is always good practice to use the correct status codes when appropriate. Furthermore, we find that they are instrumental when creating APIs out of your existing web application.

The Javascript solution#

The general strategy is to use Javascript to issue a background (AJAX) request to the server whenever the user submits the form (the callback may be attached to the form's onsubmit event handler).

If the return code for the request is a 403 (Forbidden), then launch a pop-up window with the login form, which may be retrieved with another AJAX request. Once logged-in, close the popup window, and carry on with the form submission.

Using HEAD request for performance#

The advantage of using HTTP status codes correctly is that the HEAD method may be used to quickly probe the server for the user's logged-in status. In the applications we develop at OpenWeb Solutions, we check for a HEAD request after the initial global configuration but before parsing and subsequently completing the request. Not only does this trick greatly reduce the required bandwidth for the probe operation, but it is considerably faster and more robust than the alternative of checking whether the server's response is a login form.

Implementation details#

We have attempted to profer a solution that is implementation agnostic. The basic outline described here may be used regardless of server architecture (PHP, Python, Ruby on Rails, etc). Indeed, the server-side implementation of this feature only requires handling of HEAD requests as probes of user session validity, as well as using HTTP status codes in responses, if these are not already in use. The example below, which is the preface of the index.php file for one of our applications, demonstrates how trivial the server implementation is.

 * Gateway to the program. Manage all session information and direct traffic.
 * @author OpenWeb Solutions, LLC

// Global configuration and basic session activation

// ------------------------------------------------------------
// HEAD method used to determine status
// ------------------------------------------------------------
if (Conf::$METHOD == 'HEAD') {
  if (
Conf::$USER === null)
header('HTTP/1.1 403 Forbidden');

// [Rest of program logic]

The Javascript implementation, on the other hand, is a bit more complex. A visual example of this strategy in action is shown in the slideshow below.

View the slideshow as a standalone document.

In the future, we hope to discuss the details of this solution. As always, our focus is on compliance and maintainability. Feel free to implement your own, and drop us a line on Twitter (@OpenWebSolns) if you do.

Limitations and conclusions#

This solution is intended to safeguard users from the frustration of those edge cases in which a POST request occurs after a session timeout, thereby resulting in loss of the submitted data. Our solution requires Javascript to work, but we find that it is an appropriate use of it because it helps to enhance the user's experience, without being a requirement for using the application.

We recommend this particular strategy for being clean and efficient, without consuming any additional resources on the server side.

Continue the discussion on Twitter.