Express Session cookies not being saved in Chrome? - node.js

I have an express session set up to use cookies which get stored in a database. This works perfectly in firefox, but it chrome it doesn't seem to ever save the cookie, so the session is never reflected by the client.
app.use(expressSession({
secret: data[0],
cookie: {
httpOnly: false,
secure: true,
maxAge: 14 * 24 * 60 * 60 * 1000, //14 days
},
store: new connectMongo({mongooseConnection: mongoose.connection}),
resave: false,
saveUninitialized: false,
}));
In firefox, it definitely saves a cookie as connect.sid, and saves data between page loads:
In chrome, it saves some of my browser side set cookies, such as analytics and ones I do with javascript, but connect.sid is never saved.
EDIT: so I've discovered it has to do with secure: true, but I don't want to disable it if I don't have to.
I thought it had to do with xhr.withCredentials but that didn't seem to fix it, plus the page says that it doesn't affect same-site requests, which mine always are.

Not sure where your were hosting your server but after struggling with similar problem you can use the following line, it could be that your server is hosted in places such as heroku as per this other stack overflow thread PassportJS callback switch between http and https
app.set('trust proxy', 1)

Related

Cookie is not get saved in chrome even after setting sameSite:'none' and secure: true for a MERN stack web app

After the latest updates in chrome, the browser is not saving my server cookies. Previously, it was working even it showed a warning about it. But now it is not.
Since my react app is hosted on netlify and my server runs on AWS, it is cross-origin. So, I have changed my cookie settings in express-session with sameSite=None secure options as follows.
app.use(session({
secret: 'my secret',
name: 'my-react-app',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
sameSite: 'none',
maxAge: 24 * 60 * 60 * 1000,
httpOnly: true
}
}));
After setting secure: true, it does not even work in firefox. The website is served over https. I've tried almost all combinations with these params. Am I missing anything? Any help would be appreciated.
I found the solution finally.
Actually, it has nothing much to do with express-session settings, in which I spent a lot of hours. The main reason behind this is misconfigured reverse proxy. In my case, connection between the reverse proxy and application server was not https. Because of that, the secure flag in the cookie is not applied, which in turn results into setting sameSite option to default 'lax' value. And, that's why my cookies got rejected in a cross-origin request.
To solve this, I have to set X-Forwarded-Proto in the proxy header.
Open reverse proxy configuration file
sudo nano /etc/nginx/conf.d/sysmon.conf
in my case, and add the following line.
proxy_set_header X-Forwarded-Proto $scheme;
This will forward request over https.
And you also need to set "trust proxy" in express.
var app = express()
app.set('trust proxy', 1) // trust first proxy

Express-session works wrong when website migrated from http to https?

After we migrated our website from http scheme to https (including enabling https on CDN and redirecting http to https on server), we found that our user sessions works incorrectly sometimes, that is, the user A would be recognized as user B! It seems the session ids of cookies are incorrectly parsed and maybe different users share the same cookies or session ids but all the session ids are generated by uid-safe uniquely.
The issue seems very strange and we really have no idea of the cause.
we use nodejs, Express, express-session with redis storage.
The express-session setup is as below:
app.use(session({
secret: 'xxxx',
cookie: {
maxAge: 3600*24*90*1000
},
store: new redisStore(),
resave: false,
rolling: true,
saveUninitialized: false
}));

express-session secure: true

app.use(session({
secret: "testing credentials",
store: sessionStore,
resave: true,
saveUninitialized: true,
cookie : {
httpOnly: true,
//secure: true,
maxAge : 60 * 60 * 1000
}
}));
I'm working on some security problems on my newly developed website. And after done some research online, if secure=true is set, then it will be more secure. However,
If set secure: true, then information inside session will lose every time when the user send another request. Is there a way to solve this problem? If doesn't include "secure: true" in the cookie: , then the session will last for that maxAge.
If a cookie is set with the secure flag, it will only be sent to the server by the browser over https, and not plain http. This should be the default for production environments.
However, when developing an app, you probably use plain http on your dev machine. If you set your session cookie as secure in this case (using plain http), the server will never receive it, and you will experience a new empty session on each request.
So in short, you should only set the cookie as secure if you are using https (that is, in later stages of your development pipeline, and definitely in production).
On another note, if you set maxAge, the cookie will be persisted, which is not the best practice for session cookies. Without maxAge, the cookie will be kept until the user closes the browser and not normally persisted to disk, which is the correct behaviour for session cookies.

Sharing Redis Sessions Across Node Apps

I'm busy building a platform with 3 different subdomains - example.com, auth.example.com and api.example.com. They're run with 3 separate NodeJS apps running on different ports of the server.
Here is the code setting up the sessions:
var session = require("express-session");
var redisStore = require("connect-redis")(session);
var redisClient = require("redis").createClient(config.redis);
app.use(session({
secret: config.server.secret,
store: new redisStore(config.redis),
client: redisClient,
resave: false,
saveUninitialized: false,
cookie: {
domain: "example.co.za",
httpOnly: false
}
}));
The configuration is exactly the same for all 3 apps and they're sitting on the same server. For some reason, the sessions are not being shared. I seem to remember that they were being shared a few weeks back and now things are broken - I have a sneaky suspision that this happened when we moved all the traffic from HTTP to HTTPS. Would this break the sessions? I tried to turn of 'httpOnly' in case it restricted the sessions, but no luck.
I have run redid-cli MONITOR and the session is, in fact, being saved on login (Auth App) but is not being retrieved by the other app. When I turned saveUninitialized to true, the requests to save were coming from all 3 apps - this shows that they are connected to the same Redis Store.
Any help would be great.
I think this is just a cookie issue. The browser is not sending the session cookie back on your sub-domains:
you need a leading . on the domain. e.g.:
cookie: {
domain: ".example.co.za",
httpOnly: false
}
In case that doesn't work and you are having AJAX issues see this post

secure cookies node.js + Heroku + CloudFlare

I've looked at this answer and this answer but no dice. My problem is that when my app is accessed through https://appname.herokuapp.com, everything works fine. but when accessed through https://www.appname.com (which CloudFlare aliases to https://appname.herokuapp.com), it breaks down.
Specifically, when a user logs in, the authentication is processed correctly, but the user session cookie is not set properly. So when the logged-in user is forwarded to the next screen, the request gets rejected as unauthorized.
Right now I am doing this in express:
var mySession = session({
key: "sid",
secret: process.env.SESSIONS_SECRET,
proxy: true,
cookie: {
maxAge: 86400000,
secure: true,
},
store: rDBStore,
resave: false,
saveUninitialized: true,
unset: 'destroy'
});
app.enable('trust proxy');
app.use(mySession);
Am I missing something in my node code, or in my CloudFlare settings?
Could it possibly be related to that CloudFlare puts the node app instanece behind a proxy?
Quoted from expressjs/session documentation:
If you have your node.js behind a proxy and are using secure: true, you need to set "trust proxy" in express.
app.set('trust proxy', 1)
https://github.com/expressjs/session#cookiesecure

Resources