I may just not understand exactly how Express manages sessions, but when I set the session to expire in 7 days e.g.
app.configure(function () {
app.set(express.static(__dirname + '/public'));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
expires: new Date(Date.now() + (60 * 60 * 24 * 7 * 1000)),
secret: ''
}));
});
The cookie is set to expire when the browsing session ends as opposed to the 7 days specified.
If I change the above code e.g.
app.configure(function () {
app.set(express.static(__dirname + '/public'));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
cookie: {
expires: new Date(Date.now() + (60 * 60 * 24 * 7 * 1000)),
},
secret: ''
}));
});
The cookie is set to expire in 7 days correctly; does this also expire the session on the server too in 7 days time? I would have thought the two were coupled by default.
For bonus points; in production the sessions will be stored in Redis or similar, but during developing I am storing them in memory. Is there a way I can see this data to verify when it is set to expire too?
For even more points! The sessions are not 'rolling' by default I believe? I have read that req.session.touch() will reset the session; does this reset the session cookie's TTL too? If not, how would you suggest I 'roll' the sessions e.g.
The session is initially set to 7 days.
On day 3 the user returns and the session expiration is reset to 7 days from this visit.
Etc.
So the user could have a perpetual session, so long as they were active once in any rolling 7 days.
As always, help is much appreciated!
MemoryStore is the default, it is very simple, and it do not support for TTL.
source code
If you want to access to MemoryStore, just do it like this:
var ms = new MemoryStore();
app.use(express.session({
store: ms
...
}))'
ms.all(function (err, array_of_session) {
console.log(array_of_session);
});
You should use redis or mongo to store session. For example connect-mongo, it support TTL and replica set.
https://github.com/kcbanner/connect-mongo
Session rolling?
No, you can do it yourself
read this
https://github.com/senchalabs/connect/issues/670
Related
** SOLVED **
I've been struggling with this one for a bit. Lots of similar posts out there, but none of the proposed solutions are working for me.
I'm using Express and Passport with cookie sessions. When I pass just the secret to cookieSession everything works fine:
app.use(express.cookieParser('MySecret'));
app.use(express.cookieSession('MySecret'));
app.use(passport.initialize());
app.use(passport.session());
But the default cookie is session-based, and so it clears when you close your browser. I need a time-limited cookie. So I tried using the supposedly supported options:
app.use(express.cookieParser('MySecret'));
app.use(express.cookieSession({
secret: 'MySecret',
cookie: {
maxAge: 365 * 24 * 60 * 60 * 1000
}
}));
app.use(passport.initialize());
app.use(passport.session());
And it stops working. Seemingly the cookie is set in my browser and looks good, but there's no req.user, and subsequent requests are not authenticated.
I tried using maxage instead of maxAge to no avail. I can switch to the same config, but using express.session() instead of express.cookieSession() and it does work, but the session is lost when the server is restarted.
Any help?
edit: I'm on Express 3.20.2 btw
This was user error. I'm not sure where I got the syntax for passing just the secret as a string to cookieSession() but that's invalid. It gets ignored, and actually falls back to using req.secret which is defined by the cookieParser('MySecret') call in the first place.
So that's why it was working with the original code. I still think this is a wtf moment though, because the second syntax should still work, but it doesn't. It boils down to this snippet in the cookieSession module:
if (!options.secret && req.secret) {
req.session = req.signedCookies[key] || {};
req.session.cookie = cookie;
} else {
// TODO: refactor
var rawCookie = req.cookies[key];
if (rawCookie) {
var unsigned = cookieParser.signedCookie(rawCookie, secret);
if (unsigned) {
var original = unsigned;
req.session = cookieParser.JSONCookie(unsigned) || {};
req.session.cookie = cookie;
}
}
}
So when you do pass a secret in the options for cookieSession it falls into the else block, and ends up setting a different cookie? I don't know, but it seems like a bug. If I'm using the same secret for both cookieParser and cookieSession it should be good. But anyway...
========
tl;dr it needs to be this:
app.use(express.cookieParser('MySecret'));
app.use(express.cookieSession({
cookie: {
maxAge: 30 * 24 * 60 * 60 * 1000
}
}));
We're Node + Express + Passport for authentication, and persisting the session info to Redis. I have maxAge set on the session cookie, to time out in one hour. That all seems to be working fine but the problem is, the session cookie will expire in one hour regardless of the user's activity.
Is there a way I can manually refresh/keep alive the session cookie?
You'll likely want to use the "rolling" option for your session. This "forces a cookie set on every response" and "resets the expiration date." You want to set rolling to true.
Also pay attention to the "resave" option. That "forces session to be saved even when unmodified..." You'll likely want to set that option to true as well. Note that even though the default value is true for this option, you should set the value explicitly. Relying on the default for this option, rather than setting it explicitly, is now deprecated.
Try something like:
app.use( session( { secret: 'keyboard cat',
cookie: { maxAge: 60000 },
rolling: true,
resave: true,
saveUninitialized: false
}
)
);
Here's the documentation. Look under "Options" and "options.resave": https://github.com/expressjs/session .
Yes you can!
If the cookie is unchanged on a request then it will not be resent to the browser, you can check in the developer tools under cookies to verify that. So what some, including myself like to do is to change the cookie on request where there is user activity that should extend the session. Something like the following:
req.session.lastAccess = new Date().getTime();
Another thing I've seen but I've had trouble with is to use the Session#touch:
req.session.touch()
Yes, you can manually reset the maxAge for each cookie after the user logs in:
req.session.cookie.maxAge = 60 * 60 * 1000;
Here is the connect session documentation.
Try this code:
app.use(session({ secret: 'Category', cookie: { maxAge: 6000000 }, resave: true, saveUninitialized: false}));
Bringing this question to SO since the express group didn't have an answer.
I'm setting the session maxAge = 900000 and I see that the the expires property on the session cookie is set correctly.
However, on subsequent requests the timeout is not being extended. It is never extended and the cookie eventually expires.
The session middleware docs say that Session#touch() isn't necessary because the session middleware will do it for me. I actually tried calling req.session.touch() manually and that did nothing, I also tried setting the maxAge on the req.session.cookie as well and that did nothing :-(
Am I missing a setting somewhere to automatically extend active sessions? Short of recreating the cookie manually on each request is there any other way to extend a session timeout after end-user activity?
EDIT: I experienced this problem in express v3. I'm not 100% sure but I think this note from the express changelog may have been the culprit:
changed session() to only set-cookie on modification (hashed session json)
Rolling sessions now exist in express sessions. Setting the rolling attribute to true in the options, it will recalculate the expiry value by setting the maxAge offset, applied to the current time.
https://github.com/expressjs/session/issues/3
https://github.com/expressjs/session/issues/33
https://github.com/expressjs/session (search for rolling)
For example, note the rolling:
app.use(session({
secret: 'a secret',
cookie: {
path: '/',
httpOnly: true,
secure: false,
maxAge: 10 * 60 * 1000
},
rolling: true
}));
Here is the solution in case anyone else has the same issue:
function (req, res, next) {
if ('HEAD' == req.method || 'OPTIONS' == req.method) return next();
// break session hash / force express to spit out a new cookie once per second at most
req.session._garbage = Date();
req.session.touch();
next();
}
In node I have a https server, and I use sessions with a maxage value, here's the code:
app.use(express.cookieParser());
app.use(express.session({
secret: 'secret stuff',
store: sessionStore,
cookie: {
secure: true,
maxAge: 60 * 1000 //1 minute
}
}));
I want a functionality like if the user visits the site within maxAge period (1 min in this case) the cookie timer starts over again, and he/she has 1 minute left to loose it's session id.
I see that the req.session._expires is updated (by the session middleware), but the cookie is left as it is. So the cookie will expire, a new session id connect.sid will be generated.
How can I achieve this? I thought it's automatically done by the session middleware, but seems like the expiration of cookie and expiration of session are two different things, than what session._expires is it for?
Edit
Here DanielBaulig word my problem better. As Marc B wrote in the comments the cookie expires, so the session became orphaned. That's what I want to avoid, I want to renew the cookie, when the session is touched.
Try
cookie: {
secure: true,
expires: new Date(Date.now() + 60 * 1000), // plus 1 minute
maxAge: 60 * 1000 //1 minute
}
I'm thinking the expires Date isn't being reset properly.
I understand that you can set the maxAge when starting up the app as follows:
connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})
However, i would like to implement something along the lines of "remember me" setting, how would i go about doing that?
Thanks a lot :)
Jason
You can set either expires or maxAge on the individual cookie belonging to the current user:
// This user should log in again after restarting the browser
req.session.cookie.expires = false;
// This user won't have to log in for a year
req.session.cookie.maxAge = 365 * 24 * 60 * 60 * 1000;
See connect session documentation.