State-less Session

Isn't that an oxymoron?

Ed de Moel, Jacquard Systems Research

Introduction

There are many tool-kits that make it easy to embed an application in a frame-work that offers a web-interface, and creates the equivalent of the concept of a "session" that is still well-known from the days of simple terminals.

Without such tool-kits, a web-interface would offer a "state-less" sequence of events, where each interaction between the end-user and the application is treated as an isolated event, with no knowledge of prior activities that the same end-user would have completed.
For many applications, a certain amount of recollection of prior events is desirable, if not essential, hence the desire for "web-sessions".

In those cases where the popular tool-kits cannot be used, it is important to remember that it doesn't take too much to create the equivalent of a "session" in an environment that is basically "state-less".

The basic idea

The idea of a stateless session uses the feature that each interaction between an end-user and a web-server can present a number of variables, each with their own value. When a session is established, the web-server will present a special variable to the browser (the name of this variable can be implementation-specific) with a value that uniquely identifies the session, and when the end-user communicates back to the server, this variable is included in the data-stream, so that the server can recognize the interaction as part of a session that it knows about.

Note that, as opposed to "cookies", which are stored on the computer where the browser is running, the information about the session will be stored on the server, and only a "token" that identifies the session will be exchanged between the server and the browser.

More detail

The management of a state-less session would work like this:

The initial call to an application would use a URL (Universal Resource Locator) that could look like: http://site.company.com/Application.

Whenever the program for this application is invoked, it will check the values of its parameter variables.
There should be one, let's call it SessionToken for the purpose of this discussion, that would have a value that could implement the concept of a session.

When the above URL is processed, no values for variables are included, and the receiving application will not be able to find a value for its SessionToken. Once the application becomes aware of this, it knows to start a new session. If there is no need for secured access or user-registration, a session token can be generated immediately and the application can start with its first page.
If there is a need to keep track of who is using the application, the software can transmit a login form, which would request that the end-user provide a valid identification.
Typical variables to include in such a form are (their names could be anything, let's assume the following names for the purpose of this discussion):

The login-program will check whether the username and password are correct, and, once identity is verified, the application may verify that the specific user has access to the application itself.
Such a two-phase approach allows an organization to register users in one company-wide database, and access to applications in various application-specific databases.
For an end-user this would mean that the same username and password can be used for all applications of that organization.

If there is any problem, the login form can be presented again (with all the same initial values), and some indication that "access was denied". The message should not contain information that would allow a hacker to figure out exactly which part of the transmitted information was invalid.

If all information from the login form is acceptable, the first page of the application can be displayed. The form and content of this page is completely up to the application. Calls to next pages, sub-parts or phases in the application could be implemented through hypertext links (URLs) or through forms with buttons. In either case, the application would be called at the same starting point, however, there would be a number of variables that would, at that stage, have a different value. Most of these variables would be completely application specific: these are the variables that the application needs to do its work.

There should be just one additional variable, SessionToken in this example, that always must be present (after all, if it would not be present, the program would present the login form or go back to the first page of the application...). The value of this variable, however, is also is application dependent. It could be a value as simple as 0 or 1 (1 = currently logged in), or it could be a multi-part value that contains information about the sub-parts of the application that are currently accessible and that is transmitted in an encrypted fashion.

If security is an issue, the value of the token should be complex enough that a hacker would not be able to guess (or worse: predict) its value.

That's the idea...

How long does a session last?

A session, of course, can last as long as the application is willing to allow it it last, but, in general, it does make sense to give each session a finite life-span. After all, in the days of traditional terminal sessions, it was already hard to motivate end-users to "log-off" when they were done with their tasks, and in the days of web-communication, the end-user might not even notice that there is an option to terminate an open session, and just move to the next activity by clicking on a "bookmark" in a menu of favorite web-addresses...

A simple method of setting an expiration time for a session can be implemented at the point where the application checks the value of its SessionToken. The application could store an expiration time for each token, and, when a token is presented, move to the initial page (or login form) when the token has expired.
In most of my applications, I initially set the expiration time to 5 minutes after login, and then extend the expiration time each time a subsequent interaction takes place to become 15 minutes after that interaction.


 Set token=$Get(%KEY("SessionToken"))
 Do:token'=""
 . New exp
 . Set exp=$Get(^jsrToken(token))
 . If 'exp Set token="" Quit  ; This token not recognized...
 . If exp<$$Now() Set token="" Quit
 . ; Extend expiration of token by 15 minutes
 . Set ^jsrToken(token)=15*60+$$Now()
 . Quit

 ...

Now() New h
 Set h=$Horolog
 Quit $Piece(h,",",1)*86400+$Piece(h,",",2)

How desirable is it to create sessions?

Basically, the level of desirability is often dictated by the application, and sometimes up to the whim of the programmer.

Let's use an implementation of the game of Hangman as an illustration. In this game, the end-user has to guess a word, and performs guesses by supplying characters. The opponent (in this case the application) will check the characters supplied by the end-user and for each wrong character add an element to a drawing. When the drawing is complete, it will show a person hanging from a gallows, and the player has lost the game. If the player fills in all characters of the word before the drawing is complete, the player wins.

Obviously, the application would need a way of remembering which letters have been guessed, and how many erroneous characters have been guessed.

One possible implementation would be to pass this information in variables each time the display is updated (from server to browser), and each time the end-user makes a new guess (from browser to server).
(Click here to download the M[UMPS]-program.)

Another possible implementation would be to maintain this information on the server, and update it after each interaction with the end-user.
(Click here to download the M[UMPS]-program.)


 Set ^jsrHang("Session",token,"Stage")=CurSt
 Set ^jsrHang("Session",token,"Guessed",letter)=""

In the former implementation, it will be possible for the end-user to use the "back" button on the browser to go back to the page of a previous step in the game, whereas, in the latter implementation, the application could detect that the end-user reverted to an earlier stage in the game, and proclaim a loss by default for cheating, or just continue the game, keeping in mind all activity that has occurred between the transmission of the page that is now the "current" one, and the one that was actually transmitted most recently.

Which of these two types of implementation is to be preferred, of course, is often up to the implementor of the application. In many applications (especially those where money moves between different owners) a situation where one can revert to an earlier stage is simply not acceptable; for other applications it might actually be very desirable to be able to "back up and try again"...

Notes

Ed de Moel is past chairman of the MDC and works with Jacquard Systems Research.
His experience includes developing software for research in medicine and physics.
Over the past ten years, Ed's has mostly focused on the production of tools for data management and analysis, and tools for the support of day-to-day operation of medical systems.
Ed has worked with the Greystone Group at Sanchez on a project to make GT.M more compliant with the 1995 ANSI standard, and currently works with the Department of Veterans Affairs on their project to add images to the medical record.
Ed can be reached by e-mail.