One of things that I have found annoying about XPages apps is that an application page left open in the browser for a long time will act like it is usable, but in fact the session has timed out and the page is unusable. When you try to actually submit anything the page will fail, and you will have to re-login. I work for a bank now, where they are very concerned with security so I wanted my application to work similar to most financial websites. In addition, I find a page you can't use a very poor user experience. I had some time while the project is ramping up, so I decided to do something about it.
In this post, I will go over a simple way to force the page to redirect to the login page after the session expires. I was actually surprised when I researched this that I couldn't find anyone who had already done it. I put
this Stack Overflow question in, and Stephan Wissel answered it and pointed me in the right direction. He reinforced what I suspected that I would have to do this entirely in the client.
What does it do, how does it work
The concept here is pretty simple, when you load a page it sets a timer. Whenever you submit anything to the server, or switch tabs in the application the timer is reset. The timer accepts two parameters, the time to wait, and the page to redirect to. The function does NOT log you out, that is what happens automatically by the server, this simply makes the client aware of what already happened. In my case, I redirect to the application home page, so that after the login is re-entered it goes where I want it to. It would be easy to just make the function refresh the current page.
var timeoutID;
function setAutoRefresh(refreshTime, relativePath) {
if(timeoutID){
window.clearTimeout(timeoutID);
}
timeoutID = window.setTimeout(function(){ location.replace(relativePath);}, refreshTime);
}
The same function will work for setting and resetting the timer. Not sure why you would, but if you wanted to, you could have any number of timeouts on a page by giving them different variables.
You call the function like this:
var pathArray = window.location.pathname.split( '/' );
var path = "/" + pathArray[1] + "/" + pathArray[2];
//returns relative path to application home, example: "/atm/atm.nsf"
//1860000 represents 31 minutes, one minute after session timeout
setAutoRefresh(1860000, path);
I made my timer set to one minute after the default 30 minute session logout. The way this is written now, if the time was set less then it would redirect to the page and skip the login page which to me defeats the purpose. One warning, if you miss resetting the timer then the page could redirect unexpectedly. In my application, I call the function from the onClientLoad of my layout custom control once and then in each button that perform updates. Note: If you are not using a layout custom control, then you will have to put this in the onClientLoad of every XPage.
Potential Enhancements
The code I wrote is pretty basic, maybe too basic. Here are a two ways that you could make it more robust:
- When the timer is up, you could create an ajax call to ping the server, and then redirect the page if you get returned a "Not Authorized" message. If the session is still active you could reset the timer. With this method, you could load it once, and just have it run every ten minutes, and never have to worry about it.
- Another enhancement, would be not reset the timer when you switch tabs or submit anything, but instead reset if based on a mouse moving event. I considered this but thought it overkill for the application I am writing and didn't want to be calling the function non-stop.
If anyone had any better ways of doing this, or anything to add, please comment.
August 2016 Edit:
For some strange reason David Leedy is unable to comment on my blog so I am adding his comment here.
I'm adapting this code for my day job and also a future MWLug presentation and maybe even NotesIn9. I had problems with the code as it seemed to hardcode in the level of folder nesting. I ended up using this:
var thisUrl = window.location.href;
var lastSlash = thisUrl.lastIndexOf("/");
var dbPath = thisUrl.substring(0, lastSlash);
var finalPath = dbPath + "?Logout&redirectto=" + dbPath + "/sessionExpired?OpenPage";
console.log("dbPath : " + dbPath);
console.log("FinalPath : " + finalPath);
//1 minute = 60,000 milliseconds
setAutoRefresh(60000,finalPath);
Thanks to both you Steve, and Daniel for this post and comment!