# Explicitly Ending A ColdFusion Session

By on
Tags:

Yesterday's post on the misconceptions behind clearing the ColdFusion Session scope sparked some really great conversation in the comments. Not only did I learn a thing or two, it got me thinking about the ways in which we can actually end a user's ColdFusion session. As a follow-up post, I thought it would be good to explore a few different approaches to ColdFusion session termination. All of these solutions revolve around dynamically changing a given user's session timeout; but each differs in terms of its organization and use of documented vs. undocumented features.

### Approach One: Changing The Session Timeout In The Application.cfc Pseudo Constructor

As has been demonstrated before, the Application.cfc ColdFusion framework component is instantiated for every single page request in a given application. This gives us the ability to, on every single page request, dynamically change the current settings for both the application as well as for the session associated with the given request. In this approach, we're going to listen for a URL flag from within the Application.cfc pseudo constructor; and, if detected, we're going to kill the user's session timeout for the given request.

Killing the user's session timeout is not sufficient to end the user's session; at least, not all the time. Once we kill the session timeout, we also have to clear the user's session cookies. This way, any redirects or further navigation taken by the user will prevent the ColdFusion application from persisting the current session. Remember, the timeout settings are based purely on inactivity across page requests. That said, let's take a look at the Application.cfc in approach one. Take note of both the pseudo constructor and the onRequestStart() event handler:

### Application.cfc

<cfcomponent
output="false"
hint="I define application settings and event handlers.">

<!--- Define the application settings. --->
<cfset this.name = hash( getCurrentTemplatePath() ) />
<cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) />
<cfset this.sessionManagement = true />
<cfset this.sessionTimeout = createTimeSpan( 0, 0, 3, 0 ) />

<!--- ------------------------------------------------- --->
<!--- ------------------------------------------------- --->

<!---
Check to see if we are supposed to kill the user's
currently active session.
--->
<cfif structKeyExists( url, "killSession" )>

<!---
Override the session timeout so that it will timeout
immediately (approximately - it might be slightly
delayed).

NOTE: Using a ZERO timeout seems to be ignored by
the ColdFusion framework. Hence, I am using 1 second.
--->
<cfset this.sessionTimeout = createTimeSpan( 0, 0, 0, 1 ) />

<!---
NOTE: We have to get OUT of the pseudo constructor
before we redirect the user otherwise the new
sessionTimeout value will not actually stick.

Also, we CANNOT delete the cookies in the pseudo
constructor, otherwise new cookies will be assigned
to the tiny timeout and we won't *actually* timeout
the current session.
--->

</cfif>

<!--- ------------------------------------------------- --->
<!--- ------------------------------------------------- --->

<!--- Define page request settings. --->
<cfsetting
requesttimeout="10"
showdebugoutput="false"
/>

<cffunction
name="onSessionStart"
access="public"
returntype="void"
output="false"
hint="I initialize the session.">

<!---
Set up a hit count variable so that we can see
how many page requests are recorded in this user's
session.
--->
<cfset session.hitCount = 0 />

<!--- Return out. --->
<cfreturn />
</cffunction>

<cffunction
name="onRequestStart"
access="public"
returntype="boolean"
output="false"
hint="I initialize the page request.">

<!--- Define the local scope. --->
<cfset var local = {} />

<!--- --------------------------------------------- --->
<!--- --------------------------------------------- --->

<!---
Check to see if we killed the session timeout in the
psuedo constructor. If we did, we can / should now
kill the cookies for the current session and then
redirect such that the user can get their new session.
--->
<cfif structKeyExists( url, "killSession" )>

<!---
Clear all of the session cookies. This will
expire them on the user's computer when the
CFLocation executes.
--->
<cfloop
list="cfid,cftoken,cfmagic">

<!--- Expire this session cookie. --->
value=""
expires="now"
/>

</cfloop>

<!---
Redirect back to the primary page (so that we dont
have the killSession URL parameter visible).
--->
<cflocation
url="./index.cfm"
/>

</cfif>

<!--- --------------------------------------------- --->
<!--- --------------------------------------------- --->

<!--- Increment hit count. --->
<cfset session.hitCount++ />

<!--- Return true so the page can process. --->
<cfreturn true />
</cffunction>

<cffunction
name="onSessionEnd"
access="public"
returntype="void"
output="false"
hint="I handle any end-of-session logic.">

<!--- Define arguments. --->
<cfargument
name="sessionScope"
type="any"
required="true"
hint="I am the session scope that is ending."
/>

<cfargument
name="applicationScope"
type="any"
required="true"
hint="I am the application scope parent to the given session."
/>

<!--- Output the CFID and CFTOKEN values to the log. --->
<cffile
action="append"
file="#getDirectoryFromPath( getCurrentTemplatePath() )#log.cfm"
output="ENDED: #arguments.sessionScope.cfid#<br />"
/>

<!--- Return out. --->
<cfreturn />
</cffunction>

</cfcomponent>


In this Application.cfc ColdFusion framework component, notice that we are looking for the URL flag, killSession. If detected, we are acting on it in two ways: we kill the session timeout within the pseudo constructor; and, we clear the user session cookies within the onRequestStart() event handler. For the session timeout, I went with one second. The ColdFusion documentation indicates that a timeout of zero seconds can be used; but in my experience, a zero second timeout appears to be ignored.

As I stated above, clearing the user's session cookies is an essential part of this process. If we had killed the session timeout and then immediately redirected the user back to the primary display page (so as to get rid of the URL flag), chances are, ColdFusion will reassociate the second request with the previous session before it has had a chance to timeout. So, in essence, we are actually creating a new session so as to allow the previous session to terminate without disruption (which happens within a few seconds - it's not an exact science).

To test this approach, I made use of the onSessionEnd() event handler which writes the ending session's CFID to a log file. This log file then gets included and displayed in my primary display page:

### Index.cfm

<cfoutput>

<h1>
Explicitly Ending ColdFusion Sessions
</h1>

<p>
Hit Count:
#session.hitCount#
( <a href="index.cfm">Refresh</a> )
</p>

<p>
CFID: #session.cfid#<br />
CFTOKEN: #session.cftoken#<br />
</p>

<p>
<a href="index.cfm?killSession">End Session</a>
</p>

<!--- Include the log file (for sesion ending). --->
<cfinclude template="log.cfm" />

</cfoutput>


To see the output generated by this page, check out the video above. Due to the time-sensitive behavior of this exploration, it is not something that I can easily present in a graphic.

### Approach Two: Changing The Session Timeout Using The Session Scope's Undocumented Features

In the comments yesterday, David Boyer pointed out that the ColdFusion Session scope has an undocumented method, Session.setMaxInactiveInterval( long ). This method, as you can probably gather from the name, sets the maximum amount of time that a session can be inactive (ie. the user has not made any subsequent page requests). In other words, it sets the session timeout for the current user. And, because it is a method on the Session scope, it means that we can perform this action where ever and whenever we have access to the Session.

Using this undocumented method, we can now refactor our Application.cfc to kill the user's session without having to deal with the pseudo constructor:

### Application.cfc

<cfcomponent
output="false"
hint="I define application settings and event handlers.">

<!--- Define the application settings. --->
<cfset this.name = hash( getCurrentTemplatePath() ) />
<cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) />
<cfset this.sessionManagement = true />
<cfset this.sessionTimeout = createTimeSpan( 0, 0, 3, 0 ) />

<!--- Define page request settings. --->
<cfsetting
requesttimeout="10"
showdebugoutput="false"
/>

<cffunction
name="onSessionStart"
access="public"
returntype="void"
output="false"
hint="I initialize the session.">

<!---
Set up a hit count variable so that we can see
how many page requests are recorded in this user's
session.
--->
<cfset session.hitCount = 0 />

<!--- Return out. --->
<cfreturn />
</cffunction>

<cffunction
name="onRequestStart"
access="public"
returntype="boolean"
output="false"
hint="I initialize the page request.">

<!--- Define the local scope. --->
<cfset var local = {} />

<!--- --------------------------------------------- --->
<!--- --------------------------------------------- --->

<!---
Check to see if we are supposed to kill the user's
currently active session.
--->
<cfif structKeyExists( url, "killSession" )>

<!---
Change the timeout on the current session scope.
This is an undocumented function. We are changing
it to one second.
--->
<cfset session.setMaxInactiveInterval(
javaCast( "long", 1 )
) />

<!---
Clear all of the session cookies. This will
expire them on the user's computer when the
CFLocation executes.

NOTE: We need to do this so that the redirect
doesn't immediately pick up the previous session
within the new, one-second timeout (which would
completely defeat our purpose).
--->
<cfloop
list="cfid,cftoken,cfmagic">

<!--- Expire this session cookie. --->
value=""
expires="now"
/>

</cfloop>

<!---
Redirect back to the primary page (so that we dont
have the killSession URL parameter visible).
--->
<cflocation
url="./index.cfm"
/>

</cfif>

<!--- --------------------------------------------- --->
<!--- --------------------------------------------- --->

<!--- Increment hit count. --->
<cfset session.hitCount++ />

<!--- Return true so the page can process. --->
<cfreturn true />
</cffunction>

<cffunction
name="onSessionEnd"
access="public"
returntype="void"
output="false"
hint="I handle any end-of-session logic.">

<!--- Define arguments. --->
<cfargument
name="sessionScope"
type="any"
required="true"
hint="I am the session scope that is ending."
/>

<cfargument
name="applicationScope"
type="any"
required="true"
hint="I am the application scope parent to the given session."
/>

<!--- Output the CFID and CFTOKEN values to the log. --->
<cffile
action="append"
file="#getDirectoryFromPath( getCurrentTemplatePath() )#log.cfm"
output="ENDED: #arguments.sessionScope.cfid#<br />"
/>

<!--- Return out. --->
<cfreturn />
</cffunction>

</cfcomponent>


Notice in this approach that our pseudo constructor simply takes care of defining all of the default application settings; the meat of the action takes place entirely within the onRequestStart() event handler. This time, upon detection of the killSession URL flag, we set the session timeout to one second using the setMaxInactiveInterval() method, clear the session cookies, and redirect the user. The mechanism for killing the session in this approach is exactly the same as in the previous approach; the only difference is in how we clear the session timeout.

The primary display page, index.cfm, is exactly the same in this approach so I won't bother showing it. And again, to see the output generated by this page, check out the video above. Due to the time-sensitive behavior of this exploration, it is not something that I can easily present in a graphic.

### Approach Three: Changing The Session Timeout In A Sub-Application

Both of the previous approaches work well; but at some level, I feel that they dilute the primary purpose of the Application.cfc ColdFusion framework component. Of course, that could be a completely emotional reaction seeing as this activity - killing sessions - is very much related to the framework itself. Regardless, I thought it would be interested to see if we could take the session termination and factor it out into a sub-application.

In this approach, we are going to move all of the session timeout logic into an Application.cfc contained within a sub folder of our main application. In this way, we can leave our primary Application.cfc seemingly more pristine. Here is our main Application.cfc:

### Application.cfc (main)

<cfcomponent
output="false"
hint="I define application settings and event handlers.">

<!--- Define the application settings. --->
<cfset this.name = hash( getCurrentTemplatePath() ) />
<cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) />
<cfset this.sessionManagement = true />
<cfset this.sessionTimeout = createTimeSpan( 0, 0, 3, 0 ) />

<!--- Define page request settings. --->
<cfsetting
requesttimeout="10"
showdebugoutput="false"
/>

<cffunction
name="onSessionStart"
access="public"
returntype="void"
output="false"
hint="I initialize the session.">

<!---
Set up a hit count variable so that we can see
how many page requests are recorded in this user's
session.
--->
<cfset session.hitCount = 0 />

<!--- Return out. --->
<cfreturn />
</cffunction>

<cffunction
name="onRequestStart"
access="public"
returntype="boolean"
output="false"
hint="I initialize the page request.">

<!--- Increment hit count. --->
<cfset session.hitCount++ />

<!--- Return true so the page can process. --->
<cfreturn true />
</cffunction>

<cffunction
name="onSessionEnd"
access="public"
returntype="void"
output="false"
hint="I handle any end-of-session logic.">

<!--- Define arguments. --->
<cfargument
name="sessionScope"
type="any"
required="true"
hint="I am the session scope that is ending."
/>

<cfargument
name="applicationScope"
type="any"
required="true"
hint="I am the application scope parent to the given session."
/>

<!--- Output the CFID and CFTOKEN values to the log. --->
<cffile
action="append"
file="#getDirectoryFromPath( getCurrentTemplatePath() )#log.cfm"
output="ENDED: #arguments.sessionScope.cfid#<br />"
/>

<!--- Return out. --->
<cfreturn />
</cffunction>

</cfcomponent>


As you can see, this component simply defines the default application and session settings; there is nothing here about ending sessions or clearing cookies. The display page for this approach is very slightly different; rather than using a link containing a killSession URL flag, our "End Session" link directs the user to the sub application:

### Index.cfm

<cfoutput>

<h1>
Explicitly Ending ColdFusion Sessions
</h1>

<p>
Hit Count:
#session.hitCount#
( <a href="index.cfm">Refresh</a> )
</p>

<p>
CFID: #session.cfid#<br />
CFTOKEN: #session.cftoken#<br />
</p>

<p>
<a href="./kill/index.cfm">End Session</a>
</p>

<!--- Include the log file (for sesion ending). --->
<cfinclude template="log.cfm" />

</cfoutput>


Notice that this time, the "End Session" link directs the user to the URL, "./kill/index.cfm". This "kill" sub-folder contains its own Application.cfc ColdFusion framework component which is responsible for ending the user's current session:

### Application.cfc (sub-directory)

<cfcomponent
output="false"
hint="I exist only to extend the base application and kill the session.">

<!---
Set the name of the application. It is critical that this
application have the same NAME as the root application
(in order to override the settings). However, since we
have hashed the application based on the root Appliation
file name, we have to use the same file name... which is
the current Application.cfc *minus* the current directory.
--->
<cfset this.name = hash(
reReplaceNoCase(
getCurrentTemplatePath(),
"[\\/][^\\/]+([\\/]Application\.cfc)\$",
"\1"
)
) />

<!---
Define the application session settings. Notice that we
are using a one second timeout for the session.
--->
<cfset this.sessionManagement = true />
<cfset this.sessionTimeout = createTimeSpan( 0, 0, 0, 1 ) />

<cffunction
name="onRequestStart"
access="public"
returntype="boolean"
output="false"
hint="I initialize the page request; but really, I am only here to kill the user cookies and redirect back to the root application.">

<!--- Define the local scope. --->
<cfset var local = {} />

<!---
Clear all of the session cookies. This will expire
them on the user's computer when the CFLocation
executes.
--->
<cfloop
list="cfid,cftoken,cfmagic">

<!--- Expire this session cookie. --->
value=""
expires="now"
/>

</cfloop>

<!---
Redirect back to the primary page of the root
application.
--->
<cflocation
url="../index.cfm"
/>

<!--- Return true so the page can process. --->
<cfreturn true />
</cffunction>

</cfcomponent>


You'll notice here that the only responsibility of this sub-Application.cfc is to kill the user's session. Now, this Application.cfc is not actually extending the base Application.cfc (that's such a pain in the paths); as such, the key part of this approach is that this application has the same Name as the root application. That's why I am removing the current directory from the getCurrentTemplatePath() value before I hash it and use it to define "this.name". By giving both Application.cfc instances the same name, the ColdFusion application server will use both of them to interact with the same application.

Because this Application.cfc has a single responsibility, I don't have to check for any URL flags; I simply set the session timeout to one second within the pseudo constructor and then clear the session cookies in the onRequestStart() event handler. Once the cookies have been cleared, I then redirect the user back to the root application. I like this approach because I think it cleans up the Application.cfc a bit; but, there is definitely some unease that I feel about having two Application.cfc definitions feeding into the same application.

In yesterday's post and comments, it was mentioned that clearing a session scope has some benefits related to garbage collection as well as security; in these demos, the only reason that I have chosen not to clear the session scope is because I am using the CFID in the onSessionEnd() application event handler. Had I not been using it, clearing the session would have been fine.

Because ColdFusion applications revolve around memory allocation more so than on "running" applications in the traditional sense, killing an application or a session is not something that lends particularly well to the ColdFusion framework. By tweaking session timeouts on a per-request basis, however, we can essentially kill ColdFusion sessions by asking them to terminate much sooner than originally intended. While all of the three approaches explored in this post are different, they all spring from this one central idea. I hope this exploration has perhaps shed some light on the lifecycle of the ColdFusion framework and how we can leverage it to, more or less, actively terminate user sessions.

Want to use code from this post? Check out the license.

Very information post. I agree with you about always being aware about the use of undocumented features. I think it's always a good idea to have alternatives ready in case Adobe take them away.

As soon as the CF10 prerelease program starts, I'll be putting my case forward for making setMaxInactiveInterval official. It has been around since CF7 so why not? ;)

Question, how would your code change if we wanted to kill all sessions for a list of *bad* spiders/bots? Using what you have learned recently, would your older blog posts need to modified? (I'm not sure if cookies are set with bots.)

@David,

Once have things encapsulated, or at least in one area, I don't think it matters which approach you take. Even if things were to drastically change, it would be quite easy to update.

@Eric,

With bots, the cookies are returned; however, the bots are never going to post them back to the server... so they might as well not be set at all. As far as how I would handle bots in general, I might try setting a low session timeout for everyone to begin with and then maybe only give a full session when a user logs in:

It really depends on what the situation is; some public sites might be fine operating simply on cookies alone without session management.

@David,

Ha ha ha, classic.

In method #3, you could also just extend the root Application.cfc, that might make the code a little more intuitive and would allow you to leverage other logic in the root Application.cfc.

(NOTE: This is one of the places where I wish you could reference an object by a relative path.)

@Dan,

Re: relative paths, that's exactly why I didn't do that. Admittedly, it would be a *much* cleaner approach :( Unfortunately, my testing folder is like 8 folders deep from my web root, so I didn't want to make those paths.

Relative pathing would really be the cat's pajamas!

For a simple login system for a webshop do you need to go these lengths when a user logs out using structClear? I cannot do this in the Application.cfc, or MUST I do this in the Appication.cfc instead of the act_logout.cfm page?

I cannot wrap my head around this right now, but maybe you can point me in the right direction?

@Sebastiaan,

I have never personally had to explicitly end a ColdFusion session; typically, I will just throttle the session timeouts at the start; but even that I am finding less necessary.

As far as where you can do it, you can use approach #2 in the logout page since:

session.setMaxInactiveInterval()

... should be accessible from anywhere in your request script processing.

would this work on Railo as well?

Am currently doing lots of development with Railo Barry on Jetty and Tomcat, with Apache, MySql and Ubuntu.

@Sebastiaan,

As @David said, I don't know if the Java-type stuff will work since Railo's underlying implementation is very different from Adobe's (from what I am told). Setting the session timeout stuff in the pseudo constructor of the Application.cfc, however, should be a core feature of ColdFusion as far as I know.

@Siva,

A relative path means that the path is defined relative to the current template (typically using ./ and ../ notation). An absolute path is a path that is defined from the root of the serve or context (as in /some/path/ or c:\some\path).

I think you can also mix and match a bit too; you can add relative paths to absolute paths:

c:\foo\bar\../../foo\bar

Does that help at all?

Nice stuff Ben.

I've got a related problem, well to do with sessions anyway. I'm trying to remove a particular users session based upon the actions of a super-user. ie. be able to kick someone off the site by removing their session, but not the session of the user doing the kicking!

Make sense.

I'm thinking of keeping a list of the active sessions in the server/application scope and then just doing a StructClear() on that particular session.

Any advice/tip/hints/tricks on that at all?

Apologies if you already have a post on this somewhere.

CK

Hi Ben -

I have a question about scenario 3.

Maybe there is some subtle rule that I am missing, so I looking for some guidance.

In the main App.cfc, you create a name by using a hash of the path.

In the sub App.cfc you create a name by using a hash of the main App.cfc path.

Why couldn't you have just used:

cfset this.Name = "test"

for both App.cfc's?

Thanks,

Doug

@Chris,

There's no easy way to kill another users session. The best method be to have an application scope structure like application.sessions[session.sessionId] = userId (from your user database). On every request you'd have to check that the session key exists. When you want to kick someone off, remove their sessionId from that structure.

Another way is to use something like my CfTracker project. It uses a whole bunch of undocumented stuff to give lists of sessions and allow you to stop them, as well as a few other tricks. But keep in mind that there's no future compatibility promise on something like that, as Adobe could easily change things ;)

@Ben + anyone else,

I forgot to mention that I followed this post up with my own investigation into the undocumented side of ColdFusion. I found there's a perfect method for stopping sessions, which also works around problems with setting the timeout to 1 second. Plus I've some hope that it'll make it into CF10 since Adobe added ApplicationStop to CF9.

http://misterdai.wordpress.com/2010/06/15/cf-sessionstop-ending-a-cf-session/

Ben,

This is great post.

I am good with invalidating the sessions, but I am not seeing the session really being cleared.

If I run this script from the servermonitoring cfc of the adminapi, I am not seeing the sessions disappear as you would think.

<cfoutput>
Active Session: #sm.getActiveSessionCount()#
<hr />
Listing of all Sessions<br />
<cfdump var="#sm.getAllActiveSessions()#">

</cfoutput>

@Mike,

Hmmm, there might be a delay between when the session times out and when the memory space is actually freed? I have never used the API to get that kind of insight. Perhaps Mr. Boyer can offer some insight to that?? It should be removed shortly, assuming the timeout was created and the cookies were erased.

@Doug,

I use the hash() approach just as an easy way to make sure no applications ever get the same name (I don't typically use sub-Application.cfc instances). So, yes, in the Extends="", it would have been much easier to use an app name. Sometimes, I get a little bit of tunnel vision.

@Dave,

Thanks for helping out!

Thanks Ben.

Interested to know if anyone actually sees sessions get cleared (using adminapi) early vs just being orphaned until the session timeout kicks in. I

@Mike,

As far as I know from my digging into sessions... When a session has timed out, it'll continue to exist for certain amount of time but marked as expired. It'll sit there until ColdFusion does a sweep of the sessions and destroys all the expired ones. The delay isn't usually that long, under a minute I think, but might be configurable in some XML somewhere.

If you're still seeing the session exist for longer than expected, the timeout value might not be what you expected. You might want to take a look at my CFTracker tool that provides some useful metadata on each session (unless you're using J2EE sessions).

Also, CF7 and CF8 (possibly, depending on patch level) allow an expired session to be reused if accessed before the expired session sweep takes place. So it's always an idea to clear the users cookies to prevent access as well.

"... For the session timeout, I went with one second. The ColdFusion documentation indicates that a timeout of zero seconds can be used; but in my experience, a zero second timeout appears to be ignored. ..."

I used a Java bytecode viewer (jclasslib bytecode viewer), popped open the cfusion.jar file that resides in the {ColdFusion root}/lib directory, and browsed to the coldfusion.runtime.SessionScope class. The reason why values of zero are ignored is because the SetMaxInactiveInterval method multiplies the incoming argument by 1000 before storing it in the class's private mMaxInactiveInterval field. So it looks like the CF Session handling subsystem treats this value as milliseconds.

@Graeme,

That would make sense. It seems that computer like milliseconds and humans like seconds (understandably -- how often do we write that exact code to multiple by 1000).

@Rose,

Woohoo! Thanks :D

Hi Ben,

Great write-up! I know this post is a little dated by now, but I was testing out your "Approach One" and had a question or two for you.

I'm not sure how ACF handles this, but in Railo (which I use exclusively), any time the session scope is fired up, it immediately sets the CFID cookie with an expiration somewhere in the year 2042. This never changes throughout the users session.

By adding the following code in the Application.cfc file (just below where you define the application settings), I'm able to keep the CFID cookie's expiration date in sync with the session.

<cfif isdefined("cookie.cfid")>
</cfif>


I'm wondering if this is a good idea or not. My thought is that if someone is in the middle of a session and then heads to lunch, there is no mechanism to clear the browser side session...since the user isn't "logging out", which fires off the ?killsession variable in the url.

Obviously the server side session would timeout normally and then a refresh of the page should cause the CFID cookie to be rebuilt with a new session. However, if your thoughts are that it's always best to get rid of the cookie at the end of a session, then I'm wondering if my approach is a viable option...and any impacts that this constant refresh of the cookie might have on server performance.

I never dealt with Application.cfc before because my main application's code base is 10 years old now! (That's what happens when you're the only Geek on staff!) I'm launching a separate project and need some of the modern features that the CFC approach provides. As usual, a couple of articles from Ben really put me on the right path! Watch out now!

I've been using this technique for a while, but recently I've started playing around with CF10 and it seems that you can no longer manipulate the CFID and CFTOKEN cookies!
On the face of it, this is probably a good security measure, but in this instance it seems to break the best way I know to end a session.
Does anyone know of a way around this?