12

I know this has a great chance of being marked as duplicate, but couldn't find exactly what I'm looking for

This is a common problem and I'm sure it has some well defined best practice solution

Background

  1. A single page SaaS app, has lot's of drag and drop, user can interact with it without much server communication for periods of time

  2. Server session only holds user object, using a non persistent session cookie

  3. Session expires on the server after X hours

  4. Some things are loaded only during log-in

Problem

  1. User works on the app, when done, user doesn't log out, just keeps the browser open
  2. User comes back after more than X hours (session is invalidated on server)
  3. User interacts with the app without needing a server connection (drags and drops things, text edits...)
  4. Only on the next server interaction (let's assume there is no auto save) user is thrown to login page and loses some of their work

Possible solutions

Here are some solutions I have in mind, would like to hear if there are any others, and if there is anything fundamentally wrong with any of them.

1. Never log the user out

  • How? either keep a long session, keep a persistent cookie, or javaScript "keep alive" ping
  • Pros: user doesn't need to worry about anything, fixes the problem for them
  • Cons: not PCI compliant, not secure, and needs development changes, e.g. things loaded to session only on user log in need to move to either a pub sub model (listening on event changes) or have cache timeout.

2. Local Storage

  • How? use new local storage to temporarily store state if logged out, redirect to login page, persist once logged in
  • Pros: Also base for "work offline" support, not just handling session timeout
  • Cons: harder to implement, need to do state merge of data tree, not all browsers support

3. Auto save

Every user action that changes the model, should persist immediately (or via some sort of a client side queue), e.g. if they check a checkbox, change a text field, or drag and drop something, once they are done, persist the changes.

  • How? Use an MV** framework (Backbone.js / Knockout.js / Ember.js / Angular.js etc) to bind the model, and persist on changes.
  • Pros: Seems like a clean solution, session is active as long as user is active, no client side work is done without persisting it.
  • Cons: The last action user is doing after a session timeout is lost.

4. Log the user out after session expires

this can have several approaches

  1. Ask the server "has session expired" - this is a bit of a catch 22 / Schrodinger's cat, as the mere question to the server extends the session (restarts the timeout),

    • How? Either have a server that supports such question (I don't know of any, but I come form Java land) or, one can just keep a table of session IDs, and last access time manually, and ask the server by passing the session ID as a parameter instead of the cookie, I'm not sure if this is even possible, but it sounds dangerous, insecure and bad design whatsoever.login page, persist once logged in
    • Pros: If there was such native support in servers, sounds like a clean, legitimate question (asking if user X still has a session or not without renewing it if they do)
    • Cons: If the server doesn't support it (and again, I don't know if any server or framework has this functionality) then the workaround has huge security risks potentially.
  2. One workaround I've heard is have a short session on the server side, and a keep alive client side ping, that has a maximum number of pings

    • How? Short session on server, client pings every sessionTimeOut/2, has max retries of Y.
    • Pros: Kind of fixes the problem, quick and dirty
    • Cons: Feels like a hack, handling the session renewal yourself instead of letting the server do it
  3. Client side timer

    • How? Have a timer on the client side and sync it with the server one by restarting it on every request to be equal to the max server session timeout minus some padding, after user is not sending any request to the server, UI shows a "sessions is about to time out, do you want to continue?" (like you have on online banking )

    • Pros: Fixes the problem

    • Cons: Can't think of any except the need to make sure the sync works

The Question

I'm probably missing something in the above analysis, might have some silly mistakes, and I would like your help to correct them. What other solutions I can have for this?

1
  • I use angular and django with tastypie so here's my thoughts from that point of view: 4.1 : The Authentication class used for all your resources could check and compare the time difference between now and the value of the "last-access" field on your User model. 401 is time is greater than configured timeframe. 200 otherwise and update 'last-access' field with now. 4.2 sounds like a great way to kill your server and increase costs 4.3 On android, when returning to the home screen I'm pretty sure the process is paused and that might also interfere with your clientside timer.
    – airtonix
    Jun 3, 2013 at 5:51

4 Answers 4

5

I think the most common simple solution is where you set a timer on the client end that shows a message after a certain portion of the normal timeout window has passed then forcibly logs them out right before the session would expire anyway if they take no action.

Local storage and auto-save introduce some issues with transactions and what saved really means. I have been on quite a few projects where this has turned out to be more trouble than it is worth when the user base does not understand the mechanics behind it.

Never logging out can be done where regulations permit, but it leads you into mistakes where you do not correctly handle what happens if someone is logged out unexpectedly, and all the state business becomes a little intensive to maintain if there is very much to track on an "active" user.

2

One workaround I've heard is have a short session on the server side, and a keep >alive client side ping, that has a maximum number of

How? Short session on server, client pings every sessionTime/2, has max >retries of Y. Pros: Kind of fixes the problem, quick and dirty Cons: Feels like a hack, handling the session renewal yourself instead of >letting the server do it

This is in my opinion the best solution. Why you consider it a "dirty hack"?

It makes exactly what have to be done. While the user works with the program the session will stay opened.

After the user stops to work with the program, the session will be closed.

Simple enough to be implemented.

Exactly what is needed, if I understood the question right.

1
  • Sometimes the dirty hacks are the best solutions :) thanks. You understood the question perfectly right
    – Eran Medan
    Feb 8, 2013 at 20:35
2

I'm actually creating an application that deals with this.

I started by creating a RESTful service using Django, Guradian and Tastypie. It authenticates using APIKEY only, authorisation to objects is handled by Guardian.

The django app only has one template view urlconf that loads the base.html which is ...

On the client side I created an application using Angular.

As far as authentication goes, there is a http-auth-interceptor that listens for 401 responses.

When a 401 is recieved it buffers the outgoing request and fires off an event "login-required". This might occur several times.

I have a modal popup containing a login form that is presented when the "login-required" event is heard, and it performs a login that returns a User resource ( a JSON bundle) which would also contain the APIKEY.

All buffered requests that previously resulted in a 401 response are replayed with the APIKEY now included in the Authorisation http header.

I use another angular service/factory to manage localstorage json data, and that's where I store the username and apikey.

The only piece of the puzzle left to solve is how to secure that information, and how to enforce a timeout on that information.

Perhaps use a timestamp check from last valid http request.

2
  • As a follow-up on this, I have considered making the following comparison on each tastypie authentication check: current_time > user.lastlogin_time + settings.SESSION_TIMEOUT. then return 401 if true. Each valid authentication updates the user.lastlogin_time to current_time.
    – airtonix
    Jun 20, 2013 at 6:28
  • This is quite nice and how I also thought about handling it.
    – oligofren
    Aug 27, 2019 at 13:16
1

In my case, I'm using something similar to 4.1. After the user logs in a very lightweight angular driven AJAX json request occurs to the REST API at set intervals against the server. Because of security requirements, the proprietary UI anticipates the server will maintain a session for the user which stores some protected information, templates, data, etc on the server side. This is still my preferred method from a security perspective. When dealing with sensitive data(not just hashed passwords and such), IMO storing it client side in Local Storage, etc poses a greater risk than server side(I'm sure somebody would debate that with me). Third parties use the same API when communicating with the system, but must send authentication credentials on every request.

The session on the server does have a max idle lifetime applied to it, and the session storage engine is memcached(which also has a max lifetime applied at which point the memory session will be marked expired). The lifetime need only be greater than whatever session lifetime you abstract in your application(and doesn't have to be my much). E.G. The session may not expire until it has been idle for 48 hours insofar as the server is concerned, but your code controls the actual lifetime. This could lead to resource issues if that lifetime is too great, and you do a poor job of managing the sessions.

In my case, different users can have different session idle timeouts based on their roles within the organization. The server places maximum limits on the session lifetime but as long as the user defined limits are less than those, it works just fine. Once the server expires the session, it's a moot issue as the session expiration process would have already been handled by the application gracefully. This is a requirement of the kind of business application I built.

Once the users session has been idle and is within an application specified threshold, the API will instruct the UI to display a countdown dialog(like the banks do), and once it is within a specific margin of distance in time from the expiration it gracefully logs the user out. This functionality persists across browser windows(because the server is in control), and an idle event on any window will begin the graceful timer and automated logout process(and keep them in sync).

If by chance the session expires in an ungraceful manner(the sessions get dumped on memcached), the next request that impacts the server will notify the user and move them back to square one(rarely happens, but can).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.