September

12

ColdFusion Example: Session Timeout Warning with jQuery/JS

You may also be interested in the post on refreshing session without reloading page with ColdFusion. Updated 11-Jan-2010: Improved ability to adjust timeouts and simplified code a bit.

I wrote a post on session timeout warnings with PHP; here’s a version with ColdFusion. Some of the text is the same because the method and principles are the same for both languages.

Javascript is needed to keep track of the time the user has been sitting on the page. The server does not know how long they have been sitting there. It only knows whether or not a request comes in during a session or after the session has expired and acts accordingly at that time. Too late for a warning.

Session Defined: Start to Finish

A session is defined as when a user begins and ends using or visiting a web site. It can be unlimited in length or strictly defined by a timeout period. If the site requires a log in or accesses sensitive data, it should time out after a period of inactivity. They can end a session by logging out or closing the browser.

Inactivity means the user has done nothing, made no requests of the web server, during a specified time. Ajax requests usually do not count.

Demo

The session time left is determined by the server, and, if you want to poll the server with an Ajax request, go for it. Javascript is used to keep track of the time left in the session.

The demo uses a simple log in with session timing handled by jquery and javascript. When the session expiration approaches, the user is warned and given an opportunity to restart the session. If the session time limit is reached, the user is prompted to log in again. If they ignore that prompt, the page automatically redirects to the log in form. In the demo this sequence of events takes 40 seconds to complete and is broken down as follows:

  1. Session timeout: 30 seconds
  2. Timeout warning: 20 seconds
  3. Session expired warning: 10 seconds
  4. Redirect to log in page: 10 seconds

Interrupting the User

The user’s attention can be diverted away from other open windows to the eminent session expiration by using a javascript alert in place of the jquery dialog box. Personal preference.

Code Breakdown

The application.cfc controls the session by creating non-persistent cookies for CFID and CFTOKEN so the session expires when the user’s browser closes. It also sets the session variable sessionStartTime. The sessionStartTime variable is used to illustrate the fact that the application.cfc function OnSessionStart only fires once. It does not fire every time a session is renewed or restarted.

<cfcomponent
    displayname="Application"
    output="false"
    hint="Handle the application.">

    <!--- Set up the application. --->
    <cfset THIS.Name = "sessiontest" />
    <cfset THIS.ApplicationTimeout = CreateTimeSpan(0,1,0,0) />
    <!--- CreateTimeSpan(days, hours, minutes, seconds) --->
    <cfset THIS.SessionTimeout = CreateTimeSpan(0,0,0,30) />
    <cfset THIS.SessionManagement = true />
    <cfset THIS.SetClientCookies = false />

    <cffunction
        name="OnSessionStart"
        access="public"
        returntype="void"
        output="false"
        hint="Fires ONLY ONCE when session first created and not when session renewed/restarted.">       

        <!---set cfid/cftoken as non-persistent cookies so session ends on browser close --->
        <cfif not IsDefined("Cookie.CFID")>
            <cflock scope="session" type="readonly" timeout="5">
                <cfcookie name="CFID" value="#session.CFID#">
                <cfcookie name="CFTOKEN" value="#session.CFTOKEN#">
                 <cfset session.SessionStartTime = Now() />
            </cflock>
        </cfif>

        <cfreturn />
    </cffunction>

</cfcomponent>

The log in page checks for a query string variable called ‘expired’ and, if present, deletes the session loggedin variable. This is there because the code is going to control the expiration of the session eliminating the need to compensate for browser latency. The actual session start time the time the page loads can differ by several seconds. To avoid having to add time to the session or any other fancy guesswork, when the allotted session time has expired according to the javascript timer on the page, they are done – session over.

If they are logged in, they get bumped to the index page. The rest is the logic that handles the log in form.

Note: I would not recommend handling a log in form this way. This is for demonstration only.

<cfif isDefined("url.expired") AND url.expired>
    <cfset StructDelete(session,"loggedin") />
</cfif>

<cfif isDefined("form.username") AND isDefined("form.pw") AND form.username EQ "session" AND form.pw EQ "test">
    <cfset session.loggedin = true />
</cfif>

<cfif StructKeyExists(session, "loggedin") AND session.loggedin>
    <cflocation url="index.cfm" addToken="no" />
</cfif>

Other than the log in form and a message for the user, that’s all there is to the log in page.

Handling Session Timeout

The index page handles the session timeout code. This could be a separate javascript included in every page. The first block simply determines if they are logged in. If they are not, send them to the login page. If they are, load the index page.

<!---if not logged in, send them to login page, else load the index page--->
<cfif NOT StructKeyExists(session, "loggedin") OR NOT session.loggedin>
    <cflocation url="login.cfm" addToken="no" />
<cfelse>
 <!---Load the page --->
</cfif>

Now the time variables are set and the a javascript timer is set to check the session every 10 seconds.
Javascript uses milliseconds so for clarity the time intervals multiply the number of seconds by 1,000. You could put 10000 in for 10 seconds but I think 10*1000 helps me determine that it is 10 seconds quite a bit faster. Do what is comfortable for you.

Also, a flag is set to determine if the warning dialog box has been opened and the countdown has begun.

//event to check session time variable declaration
var checkSessionTimeEvent = 0;

$(document).ready(function() {
	//event to check session time left (times 1000 to convert seconds to milliseconds)
    checkSessionTimeEvent = setInterval("checkSessionTime()",10*1000);
});

//Your timing variables in number of seconds

//total length of session in seconds
var sessionLength = 30;
//time warning shown (10 = warning box shown 10 seconds before session starts)
var warning = 10;
//time redirect forced (10 = redirect forced 10 seconds after session ends)
var forceRedirect = 10; 

//time session started
var requestTime = new Date();

//session timeout length
var timeoutLength = sessionLength*1000;

//set time for first warning, ten seconds before session expires
var warningTime = timeoutLength - (warning*1000);

//force redirect to log in page length (session timeout plus 10 seconds)
var forceRedirectLength = timeoutLength + (forceRedirect*1000);

//set number of seconds to count down from for countdown ticker
var countdownTime = warning;

//warning dialog open; countdown underway
var warningStarted = false;

The checkSessionTime function is what gets fired off every 10 seconds by the timer. It does a time comparison and opens the dialog boxes that warn the user.

function checkSessionTime()
{
	//get time now
	var timeNow = new Date(); 

	//event create countdown ticker variable declaration
	var countdownTickerEvent; 	

	//difference between time now and time session started variable declartion
	var timeDifference = 0;

	timeDifference = timeNow - requestTime;

    if (timeDifference > warningTime && warningStarted === false)
        {
            //call now for initial dialog box text (time left until session timeout)
            countdownTicker(); 

            //set as interval event to countdown seconds to session timeout
            countdownTickerEvent = setInterval("countdownTicker()", 1000);

            $('#dialogWarning').dialog('open');
            warningStarted = true;
        }
    else if (timeDifference > timeoutLength)
    	{
    		//close warning dialog box
            if ($('#dialogWarning').dialog('isOpen')) $('#dialogWarning').dialog('close');

            $('#dialogExpired').dialog('open');

            //clear (stop) countdown ticker
            clearInterval(countdownTickerEvent);
        }

     if (timeDifference > forceRedirectLength)
     	{
        	//clear (stop) checksession event
            clearInterval(checkSessionTimeEvent);

            //force relocation
            window.location="login.cfm?expired=true";
        }
}

The countdownTicker function provides a countdown inside the warning dialog box to prompt the user to act now. It uses a timer that fires every second for a 5,4,3,2,1 effect inside the dialog box.

function countdownTicker()
{
	//put countdown time left in dialog box
	$("span#dialogText-warning").html(countdownTime);

	//decrement countdownTime
	countdownTime--;
}

And, the dialog boxes either allow the user to reload the page or, if they did nothing when the warning popped up, it logs them out by redirecting to the log in page with the expired variable in the query string. Also, thanks to scube’s debugging, it now redirects to the log in if they hit the close button on the dialog box rather than the Login button.

$(function(){
                // jQuery UI Dialog
                $('#dialogWarning').dialog({
                    autoOpen: false,
                    width: 400,
                    modal: true,
                    resizable: false,
		    close: function() {
                            window.location="login.php?expired=true";
                     },
                    buttons: {
                        "Restart Session": function() {
                            location.reload();
                        }
                    }
                });

                $('#dialogExpired').dialog({
                    autoOpen: false,
                    width: 400,
                    modal: true,
                    resizable: false,
                    buttons: {
                        "Login": function() {
                            window.location="login.cfm?expired=true";
                        }
                    }
                });
});

The dialog box contents are at the bottom of the page but they could be just about anywhere in the body.

<!--Dialog box contents-->
<div id="dialogExpired" title="Session (Page) Expired!"><p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 0 0;"></span> Your session has expired!<p id="dialogText-expired"></p></div>

<div id="dialogWarning" title="Session (Page) Expiring!"><p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 0 0;"></span> Your session will expire in <span id="dialogText-warning"></span> seconds!</div>

Remember, this is just one example. There are other ways to do this. Use this, improve this, or roll your own.

Usual recommended jQuery and CF reading:

Demo

Download

 

Further Reading:

  1. ColdFusion Session Timeout with Warning and jQuery Session Refresh
  2. jQuery.ajax and jQuery.post Form Submit Examples with ColdFusion
  3. jQuery UI Autocomplete Widget with ColdFusion
  4. Using jQuery Autocomplete to Populate Another Autocomplete – ASP.NET, ColdFusion, and PHP Examples

19 Comments for ColdFusion Example: Session Timeout Warning with jQuery/JS


Don Blaire
September 15, 2009

For the longest I have been trying to come up with a solution to the session timeout issue. Thanks for providing a way to notify the user that their session is about to timeout.


jen
September 15, 2009

You’re welcome.


James
January 8, 2010

Awesome Tutorial/Script. This is think is a great must have. Again, thanks for providing a way to notify your users that their session is about to timeout.


James Tanner
January 10, 2010

Hmm this is just what im looking for, but i d/l the demo, chucked it straight onto my server, and it doesnt work the same as the demo on this site!

link to mine is: http://mydemos.redgweb.co.uk/expire/login.cfm

take a look. No warning, just box says timed out then instant redirect

am i missing something? :(

(Win 2003, IIS6, CF8.0.1)


jen
January 10, 2010

@James

My bad. I updated a line:

//time session started
var requestTime = new Date();

Try putting that in instead of the toScript function.

I thought I updated the zip. It's updated now.

Let me know if that takes care of it for you.
Jen


James Tanner
January 10, 2010

Yep that fixed it :)


James Tanner
January 11, 2010

Hi Jen,

Sorry to be a pain, but I have problems changing the timeout. Ive changed it in what i believe all the correct places (eg, application.cfc and the scripts in index.cfm)

But it goes a bit odd, the seconds jump in 3 or 5 second staggers.

Am I doing something wrong?


jen
January 11, 2010

@James
I adjusted the code. The two javascript intervals I had running were colliding with each other. Now all you have to do is set your timing variables in the js and away you go. The new files are in the zip but you may want to clear your cache before downloading it again.


James Tanner
January 11, 2010

Hi Jen,

Many thanks for that, that seems to of done the trick :)

Awesome script for the projects folder! I can see this being used a few times


Gregory Matthews
February 2, 2010

Hey Jen,

What a bizarre coincidence! I've been using cfajaxproxy to do exactly the same thing as your tutorial here. Exactly.

The problem with cfajaxproxy is all of the files, aka, collateral damage, it brings in with it on page load (colliding with css definitions, frameworks, etc.).

I was wanting to change it over to JQuery (since that is what we us in our CF App), but am not proficient enough to get it done any time soon.

And then I find this! Perfect.

Thanks for your contribution to the community.

Best,

Gregforey


jen
February 2, 2010

You're welcome! So glad it helped out.


Laura
February 22, 2010

I'm new with coldfusion developer and I really like this option of session timeout, but I need a tip…I have many cfm files that need to be use session timeout but if I paste the script code in each one its gonna be a hard work, I try to put the code in an application.cfm file to avoid put it in each one, but it doesn't work….Do you have any idea? It will be of great help…!!! Regards


jen
February 22, 2010

@Laura
The javascript (jquery) can be included like any other javascript file or tacked on to a javacript file that you already include on your pages.
And, the html for the dialog boxes can be included in the OnRequestEnd.cfm like you would for a common footer.
http://bit.ly/aFJLcX


Laura
February 23, 2010

Hi Jen,
Thank you very much for the idea, but still involve entering into nearly 200 pages to paste the <sript>, I was thinking include it in application.cfm that I think it run at beginning of each page as a web.config, am i right? And so avoid entering all pages, is this possible?


jen
February 23, 2010

@Laura
You could use a find/replace to put the script file in. Dreamweaver and Coda make that very easy. 200 files is quite manageable. 20,000 would be another story.

I haven't used the web.config with any application other than .NET.


Laura
February 23, 2010

Thanks Jen!!! You right maybe 200 file aren't lot, but I can find a better way, add the function "onRequestEnd" in application.cfc and manage the script and the html in other file that includes in the function, now I only have 1 application.cfc file, the js files and 1 html file without modify other files…
Your help and your example have been so helpful!!!


Mitul
April 16, 2010

Hi Jen ,Thanks for contributing.

I have slight problem with this logic. I hope you can help me in modifing. In my case, our client has got big page with lots of form fileds to be filled in which takes ages.

I want to have a pop up messge to inform about session expiry time but upon clicking I donot want to refresh page as client is still in middle of filling.

Instead I want to refresh session and allow client to work on current page.

Any ideas?

Thanks


jen
April 16, 2010

@Mitul
I have been working on a solution for long forms. I am testing it now and will put up another blog post when I am confident it works as expected.


sooraj
May 25, 2010

very nice article
thanks..keep posting

Leave a comment

Why ask?

 

« | »