Handling 2 sid in express session - node.js

I have a scenario below as
On browser I open a website in which after getting authenticated with the system(i.e. access.abc.com) I get a cookie and I set it on client, i.e. connect.sid with domain as .abc.com
On same browser I open another webiste i.e. xyz.abc.com that also generates session cookie(after getting authenticated from the same i.e. access.abc.com) with same name but with different domain as xyz.abc.com(basically this is what this website sets)
Now if I send a request to any api on xyz.abc.com, I see 2 connect.sid going.
My question is which cookie will be picked by express-session of access.abc.com when xyz.abc.com send a request?
Below is the setting for express session at access.abc.com
var RedisStore = require('connect-redis')(expressSession);
var session = expressSession({
key: 'connect.sid',
store: new RedisStore({host: config.session_redis.host,
port: config.session_redis.port,
ttl: 2*24*60*60 //in secs
}),
resave: false,
saveUninitialized: false,
secret: '234567',
cookie: {
domain: '.abc.com',
maxAge: 2*24*60*60*1000 // in ms
}
});

My question is which cookie will be picked by express-session of access.abc.com when xyz.abc.com send a request?
Looking at the code, I think that it will pick the one in the first Cookie header it encounters in the request headers, so the question becomes "which cookie will the browser put in the headers first?" (which I can't answer because I have no idea).

Related

cookie confusion with session storage

I am using the following Node.js code to create a 'session store' to keep user information. These text files are kept in a folder called "session-store":
var session = require('express-session');
var FileStore = require('session-file-store')(session);
app.use(session({
store: new FileStore({path: './session-store'}),
// using FileStore with express-session
// as the store method, replacing the default memory store
secret: 'secret_key',
name: 'myadmin',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 60000, httpOnly: true, secure: false }
}));
app.get('/', function (req, res) {
if (req.session.views) {
req.session.views++;
} else {
req.session.views = 1;
}
});
My text file which contains the session information seems to generate properly. However I have some confusion regarding its proper usage. In my cookie (.txt) file, it reports the "views" correctly, such as ""views":1". However if I define another variable, such as "req.session.broadcast = String(req.body.usr);" I do not see this information in my text file...why would this not be inclusive? Is this because the .txt file containing the cookie session storage information is generated only on the initial 'route' (i.e. the "app.get('/', function (req, res) {...do stuff}") and no other place in the Node.js code? (NOTE: I have "req.session.broadcast" set in a different route other than the 'homepage' route...which I guess is when the cookie file gets generated...possibly?).
I am simply attempting to properly manage users...therefore I want to be able to have certain session variables properly set and tracked for each unique user browser.
Are the "req.session.user" and/or req.session variable(s) 'hard coded' variables? I believe they get set when the browser is directed at the webpage, however how can they be used to terminate a session? Do they automatically become null if the user closes their browser (using the "x" in the right top corner) OR if the user directs their browser to another webpage...?
Any help with these questions and any other advice would be GREATLY appreciated.

Connect session undefined when loading new page.

I'm a bit new to sessions and now when I'm trying to use them the session is always undefined for me when coming to the next page after a successful login as an example.
If my login is successful I do the following
var session = req.session;
session.user_id = String(item._id);
session.user_secure = security.security(session.user_id);
Then I redirect to another page:
res.writeHead(302, {
'Location': '/backstageArea'
});
res.end();
And then I try to fin the session again doing this:
var session = req.session;
console.log("uid: " + String(session.user_id));
console.log("hid: " + session.user_secure);
which results in the session being undefined.
these are my last three things in my app.configure:
app.use(express.cookieParser());
app.use(express.session({secret: 'secret', store: store, key: 'sid', cookie:{secure:true}}));
app.use(app.router);
Could it be since I'm redirecting to a new page that I loose the session?
Or am I doing something else wrongly?
By using cookie:{secure:true}, you tell your express application and browsers to send that cookie over https only.
So if you don't use https, you can remove secure: true
Secured cookies are useful feature to protect your sensitive cookies from mand-in-the-middle attack, They are much more useful when you use both http and https on the same domain.
If you want to use https on via nginx or apache, you may need:
app.set('trust proxy', true); // if remove this line, express will refuse to send https cookie to nginx or apache
var session = req.session;
session.user_id = String(item._id);
session.user_secure = security.security(session.user_id);
edit to
req.session.user_id = String(item._id);
req.session.user_secure = security.security(session.user_id);

How to keep alive an NodeJS Passport session

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}));

ExpressJS session expiring despite activity

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();
}

Shared Sessions between Node Apps?

I currently have two separate node apps running on two different ports but share the same backend data store. I need to share users sessions between the two apps so that when a user logs into through one app, their session is available and they appear to logged into the other app. In this case, its' a public facing website and an administrative backend.
Our setup is the following:
node with express
passport is being used to handle auth with Local Strategy
we're using connect-redis to allow us to share sessions via redis.
our domains look like this: www.mydomain.com and adm.mydomain.com
The config for for session stuff (and redis) is the same for both apps:
session: {
options: {
secret: "my secret",
cookie: {
domain: "mydomain.com",
maxAge:1000*60*60*24
}
},
redis: {
host: 'my host',
maxAge: 86400000,
secret: "my secret"
}
}
The config for session stuff in app.js looks like this:
if ( app.settings.env === "production" ) {
session.options.store = new RedisStore(session.redis);
}
app.use(express.session(session.options));
app.use(passport.initialize());
app.use(passport.session({ secret: 'a different secret' }));
What I expect it to do: Allow us to see the same session id in the cookie between the two apps.
So my question is: How do I set up express, redis and passport so that you can have sessions shared across different subdomains?
Maybe a bit outdated, but at this time, Express-session can recognise domain option for cookie. According to source:
function session(options){
var options = options || {}
// name - previously "options.key"
, name = options.name || options.key || 'connect.sid'
, store = options.store || new MemoryStore
, cookie = options.cookie || {}
...
And this is for setting cookie:
var Cookie = module.exports = function Cookie(options) {
this.path = '/';
this.maxAge = null;
this.httpOnly = true;
if (options) merge(this, options);
...
So, something like this will work for current 1.10.1 master:
secret: "my secret",
cookie: {
domain: "mydomain.com",
Express-session does not seem to recognize the "domain" option for cookies hence your problem. The cookie storing the session id is automatically tied to the domain for each app and so it cannot be shared.
One option is to write your own single-sign-on module to share sessions across webapps. It would probably live in an app.use() declaration fairly early in the execution order and would simply create a separate cookie (which would be cross-domain), create a separate SSO session id, and store the SSO id in this new cookie. Afterwards, you simply cross-populate req.session and req.sso-session as needed.

Resources