** 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
}
}));
Related
This is my first web development and my first use of a database.
With help of this Q&A I understand the purpose of sessions.
Up to now I have used 'express-session'.
const session = require('express-session');
let sess = {
//store: ,
secret: cryptoString,
resave: true,
saveUninitialized: true,
cookie: {
path: '/',
maxAge: 8 * 60 * 60 * 1000, //h * min * s * ms
},
name: 'data',
}
server.use(session(sess));
server.post('/lgn', (req, resp) => {
let session = req.session;
});
I have uploaded my code to heroku and it works. But I get the warning:
"connect.session() MemoryStore is not designed for a production enviroment, as it will leak memory, and will not scale past a single process."
Another Q&A gave me an impression of the problem. Now I'm confused about the class Session in my back4app database. I guess, I should have used them instead of the server memory. But how? I was looking for a simple, straightforward example and have found nothing.
Could you provide an example please? The Parse Doc is not enough for me. A coded, running example would be very helpful.
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}));
I am looking for a non-cookie based session management in node.js, something like pass a parameter in the URL like &session_id=. It will know that a session has expired when a request comes with an session_id. I've looked at connect library, but it looks that it is cookie based only.
Warning
Passing the session id as a GET parameter is considered bad practice. Why? It is dangerous because people don't usually care about session id and they will probably publish/share links with their session ids inside.
It's also a problem because when a user clicks an external link on your web, and goes to another site, that new site will be able to see the session_id in the referrer link.
So I don't think it is a good idea. Cookies are more secure.
Have a look at: Session Hijacking
For every request you receive, you will get all of the client cookies accordingly.
You can also set client cookies in the response HTTP headers using "Set-Cookie."
Using a GET parameter is unsafe. Any user could accidently share their session ID, but if you want 100% security, I'd share session IDs via cookies, and I would use HTTPS to prevent snoopers from stealing cookies.
You can use localstorage or sessionStorage..
almost same as cookie
not a cookie
better than a cookie!
More info: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage
It's very -very- easy to use... in Js for example:
<script>
// check if Storage is avaible
if(typeof(Storage)!=="undefined") {
// Save data to local storage (no exiparion date)
localStorage.setItem("name_always", "bxx");
// Save data to the current session (removes when the tab is closed)
sessionStorage.setItem("name_now", "bxx");
} else {
// No Storage support...
}
// Access to stored data
alert( "For only now, my name is: " + sessionStorage.getItem("name_now"));
alert( "Every day, my name is: " + localStorage.getItem("name_always"));
</script>
Tags: javascript html5 local-storage session-storage
You can use sessions with a store in node.js. For example, you have express application and want to use session like system in your webapp. You can use connect-mongo module for this. This will let you store your session in db. In your app.js
var express = require('express'),
, mongoStore = require('connect-mongo')(express);
var app = express();
app.configure('all', function () {
app.use(express.session({
secret: "terces",
cookie: { maxAge: 24 * 60 * 60 * 1000 },
store: new mongoStore({
url: your_db_url
})
}));
app.use(function(req, res, next) {
res.locals.session = req.session;
next();
});
});
With basic code above, you have session in express that you can use it in your controllers and views directly. In your controller;
app.post('/blog/create/?', function(req, res, next) {
if (!req.session.user) {
next("You need to login in order to create blog!");
}
});
In your view, you can use session.user in order to generate profile menu for example.
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();
}
I'm (almost) successfully using Node.js with Express and Redis to handle sessions.
The problem I'm having is that the session is not kept when I use res.redirect().
Here is how I can see it :
req.session.username = username.toString();
console.log(req.session);
res.redirect('/home');
The console.log() prints :
{ lastAccess: 1322579131762,
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 29 Nov 2011 15:06:31 GMT,
originalMaxAge: 60000 },
username: 'admin' }
Now, here is the following code :
app.get('/home', [app.requireLogin], function(req, res, next) {
// Not showing the rest as it's not even getting there
// Instead, here is what's interesting
app.requireLogin = function(req, res, next) {
console.log(req.session);
This console.log() prints out this :
{ lastAccess: 1322579131775,
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 29 Nov 2011 15:06:31 GMT,
originalMaxAge: 60000 } }
Clearly, the 'username' object has disappeared. The session has not kept it, and just rebuilt a new one.
How can I solve this? Don't hesitate if you need any information.
Here is the code where I set the session management :
app.configure(function() {
// Defines the view folder and engine used.
this.set('views', path.join(__dirname, 'views'));
this.set('view engine', 'ejs');
// Allow parsing form data
this.use(express.bodyParser());
// Allow parsing cookies from request headers
this.use(express.cookieParser());
// Session management
this.use(express.session({
// Private crypting key
secret: 'keyboard cat',
store: new RedisStore,
cookie: {
maxAge: 60000
}
}));
this.use(app.router);
});
Here is the whole project (I mean, parts of it), on gist : https://gist.github.com/c8ed0f2cc858942c4c3b (ignore the properties of the rendered views)
Alright, I found the solution. The problem is that the time in maxAge was added to the current date. So, in the browser side, the cookie was set to expire at the GMT time shown.
The problem was the following : I use a virtual machine to test node.js, and, you know... sometimes, you suspend your machine.
Well, what happened is that the machine's time was two days late. So, whenever the cookie was set on the server side, the client side thought the cookie was already expired, since my host machine was not two days late.
Another stupid outcome.
Did you try with different browsers ? Are you keeping the same session id between page redirects ?
You could add req.session.cookie.expires = false; before redirecting...
Your code looks pretty solid, but is there a reason you're using client.end()? It forcibly closes the redis connection and is not clean. I don't think you need it at all:
https://github.com/mranney/node_redis/issues/74
I am not sure about the underlying architecture for connect-redis, but I'm wondering if calling client.end is what's resetting your sessions. What happens if you take those out?
I was having a similar problem in that I was setting something on the session that was not persisting outside the app.get() it was set in.
My problem turned out to be that I was not doing a res.redirect() at the end of my app.get(). Looks like I was setting something on a request object and then allowing it to get garbage collected.
I added a res.redirect( '/nextmethod' ) and the data persists just fine.
Surely you need to save that session in some way, this might work.
req.session.regenerate(function(){
req.session.username = username.toString();
res.redirect('/home');
});