Seperate Cookie and Session expiration #328

Closed
DanielBaulig opened this Issue Jul 22, 2011 · 12 comments

Comments

Projects
None yet
9 participants

Currently the session middleware does not differentiate between the expiration of the cookie and the session. At a first glance this seems logical and shouldn't harbour any problems. However, there are some propably not totally uncommon use cases where this will get in your way. Let me explain:

What you currently have
Imagine a situation where you want a users session to expire, if there is no activity for 1 hour from that user anymore. You go and set your cookie maxAge to an hour. The current system will do this, if activity is defined as http requests. Due to the nature of node and its capability to seemlessly interact with the network in general though, activity might not be http requests, but an open websocket connection, a ssh session or ICMP ping packets captured with node-pcap. In this case you would grab the session from the session store, instanciate it, call touch() on it and save it again. This would work for the session in the session store, but it will not keep the cookie from expiring in the browser. The next time the user hits the page, his browser session will have expired nevertheless, since the cookie timed out and will not be transmitted.
Setting the cookies expire to never won't cut it here either, since the session expiration is bound to the cookie expiration. Sessions wouldn't expire at all anymore.

What you would want
A system where cookies and session expiration are seperated from each other. Given the same example as above, you could still set the session expiration to an hour, but the cookie expiration to never. This woul prevent the browser from discarding a cookie assoicated with a sessino, that is still valid, since it was touched by other means than http.

What you would need
Not much. There is the lastAccess attribute in the session object, that provides all the information required to determine a session timeout. The only thing you would need is an additional parameter to session store (and possibly to the session middleware creator) that gives a sessionMaxAge. If the parameter is given, instead of checking against the cookie expiration when getting a session from the store, the store would check against the session's own expiration (lastAccess + sessionMaxAge). If no sessionMaxAge is given, the cookie's originalMaxAge could be used instead. That way the change would not break any existing code but would provide the ability to seperate session expiration from cookie expiration.

What do you think? Please tell, if something isn't clear, I will elaborate. If there is any interest I would be willing to provide a patch.

Member

tj commented Sep 5, 2011

I get what you're saying, though I'm not sure I get the use-case for when you would want to disassociate the session data with the cookie. The primary reason for coupling the way I do is just simplicity, but if we have a few use-cases that are common enough I'd consider it

weepy commented May 1, 2012

Apparently this is a use-case (from http://www.danielbaulig.de/socket-ioexpress/)

Oddi 
on March 12, 2012 at 17:25 said:
When you do session.touch().save() it updates the session object in redis or 
memorystore or whatever, but does it update the cookie in the browser if the 
user is idle ie. no activity, only heartbeats from socket.io? Does the cookie 
and headers get sent when socket.io is in websocket mode or only with 
html-file, json-polling etc

Reply ↓

Daniel Baulig
on March 13, 2012 at 19:40 said:
No, it won’t for WebSocket or Flash transports. It will make the cookie expire
in the browser. Thus the method described here will actually not prolong
the session lifetime for the next HTTP request. I’m curios that no one ever 
noticed it up until now. Basically it’s fixable if the way Connect handles it’s
sessions would be changed. Connect does not differentiate between the
lifetime of a session and the lifetime of the cookie holding the session id. 
What you would need is to increase the cookie lifetime to never expire, 
while keeping the lifetime of the actual session bound to the lifetime of the
server side session data. Please see this Connect issue for additional 
information. The patch was never made afaik.

manast commented Jun 12, 2012

+1

Member

tj commented Jun 12, 2012

yeah definitely, i dont disagree at all, I think by default they should be the same but we should have an option to specify the length in the store itself

Contributor

defunctzombie commented Jun 12, 2012

How would such a scheme work for cookie sessions? I mean, technically as long as you still transmit a valid session id then the session remains valid. The backend could choose to otherwise invalidate a session regardless of whether the session info in a cookie is valid or not?

Member

tj commented Jun 12, 2012

short cookie sessions would be screwed I guess

Contributor

defunctzombie commented Jun 12, 2012

:'(

bendiy commented Feb 5, 2013

+2

bendiy commented Feb 8, 2013

Here's a work around for one use case.

When you don't want the browser cookie to expire, but need to have sessions expire and you're using something like websockets that doesn't make http request to update your browser cookie. You can override the "cookie" modules serialize() function to not set the "expires" property. This will make the browser cookie a "session" cookie, but still allow your persisted sessions to have an expires value.

// Stomp on Cookie's serialize() to not send an "expires" value to the browser.
// This makes the browser cooke a "session" cookie that will never expire and only
// gets removed when the user closes the browser. We can still set express.session.cookie.maxAge
// so our persisted session gets an expires value, but not the browser cookie.
require('express/node_modules/cookie').serialize = function(name, val, opt){
    // Need to add encode here for the stomp to work.
    var encode = encodeURIComponent;

    var pairs = [name + '=' + encode(val)];
    opt = opt || {};

    if (opt.maxAge) pairs.push('Max-Age=' + opt.maxAge);
    if (opt.domain) pairs.push('Domain=' + opt.domain);
    if (opt.path) pairs.push('Path=' + opt.path);
    // NOTE - Override here, skip this.
    //if (opt.expires) pairs.push('Expires=' + opt.expires.toUTCString());
    if (opt.httpOnly) pairs.push('HttpOnly');
    if (opt.secure) pairs.push('Secure');

    return pairs.join('; ');
};
@ghost

ghost commented Aug 25, 2013

I use the codes, When don't want the browser cookie to expire, but need to have sessions expire :

app.use(function(req, res, next){
    res.on('header', function() {
        if (!req.session) return;
        if (req.session.cookie.expires==null) return;
        req.session.cookie.expires = new Date(Date.now() + 1000*60*60*24*365)
    })
    next()
});

// express  session storage
app.use(express.session({
  secret: 'abc',
  cookie: { maxAge: 900000 },  
  store: new ... 
}))

Hi all: is expiration time of both session and cookie binded in the recent versions? I'm just setting a random value in a session's variable to force the cookie to be updated. I know that this is not the correct way. Any new workaround or any reference will be appreciated. Thanks in advance

Contributor

jonathanong commented Nov 18, 2013

i'm going to close this for now. i'll accept a good PR, but personally i feel like this isn't a 99% use case and would rather refer people to a better, 3rd party session module if they wanted this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment