Express-Session is working in development environment, as it sets the "connect.sid" cookie in my browser. However, in production it's not storing the cookie, and instead of using the same session - it creates a new one every time. I believe that the issue would be fixed if I can somehow save third party cookies, as my app was deployed using Heroku. Lastly, I have also used express-cors to avoid the CORS issue (don't know if this has anything to do with the cookie issue). I have set {credentials: true} in cors, {withCredentials: true} in Axios, as well.
Heroku uses reverse proxy. It offers https endpoints but then forwards unencrypted traffic to the website.
Try something like
app.enable('trust proxy')
And check out
https://expressjs.com/en/guide/behind-proxies.html
Issue Solved! -> Add sameSite: 'none'
Full Cookie config (express-session) for production:
cookie: {
httpOnly: true,
secure: true,
maxAge: 1000 * 60 * 60 * 48,
sameSite: 'none'
}
Adding a "name" attribute to the session config worked for me:
{
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
proxy: true, // Required for Heroku & Digital Ocean (regarding X-Forwarded-For)
name: 'MyCoolWebAppCookieName', // This needs to be unique per-host.
cookie: {
secure: true, // required for cookies to work on HTTPS
httpOnly: false,
sameSite: 'none'
}
}
Related
I have read a lot of other similar questions, but I couldn't solve the issue.
My setup is Node + Express + PassportJs and everything works in development, but I have problems on production.
With the following code, I see that the session cookie is sent back in the response, but I also get a message saying that it won't be applied as SameSite is lax (the default) and the response comes from another site (frontend and backend do not have the same origin).
app.use(
session({
secret: "foo",
resave: false,
saveUninitialized: false,
store: MongoStore.create({ mongoUrl: process.env.MONGO_DB_CONN_STRING! }),
cookie: { httpOnly: true }
})
);
So I changed it to this, so to specify SameSite and Secure in production, but at this point, no cookie is set anymore!
app.use(
session({
secret: "foo",
resave: false,
saveUninitialized: false,
store: MongoStore.create({ mongoUrl: process.env.MONGO_DB_CONN_STRING! }),
cookie: isProduction ? { httpOnly: true, sameSite: "none", secure: true } : {} // <-- only change
})
);
What could be the cause? I've tried to fix it by playing with CORS (no success) and other 100 things. Yet it seems some quirk I am missing.
depending on what service you use to deploy your API(netlify, render.com, heroku other...) you have to enable proxy
this.app.enable('trust proxy');
it fixed my issue
I am following Ben Awad full stack tutorial with same stack (
React
TypeScript
GraphQL
URQL/Apollo
Node.js
PostgreSQL
MikroORM/TypeORM
Redis
Next.js
TypeGraphQL
Chakra
)
But newer versions (the video was 2 years old), in 2:59:59, according to the video, when we make a register request through browser(client side) the qid cookies was supposed to get sent automatically but it doesn't work for me. Things work fine when I make request through my server (localhost port 5000, redirect to https://studio.apollographql.com/sandbox/explorer) but when it come to browser I successfullyy register the user but the cookies was not saved.
Here is the code I built in my server to set the cookies (redis connected):
app.use(
cors({
origin: ["http://localhost:3000", "https://studio.apollographql.com"],
credentials: true,
})
)
app.set("trust proxy", true);
app.use(
session({
name: "qid",
store: new RedisStore({ client: redisClient, disableTouch: true }),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, //10 years
httpOnly: false,
sameSite: "none",
secure: true, // cookie only works in https
},
saveUninitialized: false,
secret: "123456789",
resave: false,
})
);
Thanks guys and I appreciate you guys a lot.
I solved it: set sameSite: 'none' when you want to save cookie through sandbox and lax when you want to save it with browser.
I've been researching this for hours now. What could be the reason why the cookies are not being saved in the browser? I'm using express-session. Below are the pieces of code I'm using.
const app = express();
// CORS config
app.use(cors({
origin: process.env.API_URL,
credentials: true,
optionsSuccessStatus: 200
}));
app.use(cookieParser());
// Where the sessions are stored
const MongoDBStore = new MongoDBSession({
uri: process.env.MEDIRECORDS_URI,
collection: "sessions"
})
app.set("trust proxy", 1);
const oneDay = 1000 * 60 * 60 * 24;
app.use(session({
name: "irmp_session",
secret: process.env.AWS_SESSION_KEY,
resave: false,
saveUninitialized: false,
maxAge: 7200000, // 2 hrs validity
store: MongoDBStore,
cookie: {
path: '/',
sameSite: false,
secure: false,
maxAge: oneDay
}
}))
When I try to login using the frontend, the login is successful, the session is stored in the database. However, when I check the cookie storage, it is empty.
After spending hours of researching, I learned that this is due to Chrome's cookie updates. Here is what the update is all about.
As the link states, for a cookie to be saved in Chrome and if it is really needed to set the sameSite to none, developers should set the secure option to be true. Default value of sameSite if not set is lax.
Hope this helps anyone who might encounter the problem.
If anyone here uses heroku or render.com for free, I added all the answers above but it is still not working. I have tried another solution here which is add app.set("trust proxy", 1); before app.use(session(sessionSettings)) and it now saves cookie to different browsers.
Thank you so much for sharing it. I was stack on this for 2 days now, in localhost things worked perfectly, but after deploy my MERN app in differents servers, cookie stoped working...
using express-session:
app.use(session({
.......
.......
cookie:{
maxAge: 24*60*60*1000, //please change it based on your needs
secure: app.get('env') === 'production'?true:false,
sameSite: 'none'
}}));
this will solve the problem!!
Full warning message:
A cookie associated with a resource at http://127.0.0.1/ was set with `SameSite=None` but without `Secure`. A future release of Chrome will only deliver cookies marked `SameSite=None` if they are also marked `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5633521622188032.
However, I set cookies like:
res.cookie("token", token, {httpOnly: true, sameSite: 'none', secure: true});
Is there a way to get rid of this warning?
For a cookie required in a third-party or cross-site context, you should set both SameSite=None and Secure, as you are doing in your original example.
First question though - do you definitely need this cookie to be cross-site? In other words, are you expecting different sites to make a request to yours that require this cookie to be sent? Examples here would be if your site is embedded within an iframe on another site, hosting images where you want to have cookies included, or creating a token for additional security on a cross-site form submission.
If not, consider SameSite=Lax for this cookie instead. That way it will only be sent for requests within your site.
However, when you are developing on 127.0.0.1 or localhost you generally do not have a certificate for a valid HTTPS connection. I would suggest, in Express, using app.get('env); to get your current environment ('development' or 'production') and then using that to choose if you set Secure or not.
For example:
const express = require('express');
const app = express();
if (app.get('env') !== 'development') {
// production settings, assume HTTPS
app.set('cookie config', { httpOnly: true, sameSite: 'lax', secure: true });
} else {
// development settings, no HTTPS
app.set('cookie config', { httpOnly: true, sameSite: 'lax' });
}
// Later on when setting a cookie within your route, middleware, etc.
res.cookie('token', token, app.get('cookie config'));
You could also set up multiple cookie configs if you have different use cases on your site.
if (app.get('env') !== 'development') {
// production settings, assume HTTPS
app.set('cookie config 1p', { httpOnly: true, sameSite: 'lax', secure: true });
app.set('cookie config 3p', { httpOnly: true, sameSite: 'none', secure: true });
} else {
// development settings, no HTTPS
app.set('cookie config 1p', { httpOnly: true, sameSite: 'lax' });
// Assumes that I'm hosting all my test sites under localhost,
// so the browser won't actually see them as 3p
app.set('cookie config 3p', { httpOnly: true, sameSite: 'lax' });
}
You could also look up creating a self-signed certificate for your localhost environment, but that can be a bit of a pain. If you're going to do that, the effort might be better put into using some kind of container or vm for development.
I'm building a project with authentication. I'm using Node+React. I set an express session cookie on the back-end and I want a component in react to read that cookie to see if the user is authenticated or not. For some reason I can not access that cookie from the react(client-side)... Maybe someone could help out?
BACK:
app.use(session({
name: process.env.SESS_NAME,
resave: false,
saveUninitialized: false,
secret: process.env.SESS_SECRET,
cookie: {
maxAge: parseInt(process.env.SESS_LIFETIME),
sameSite: true, //strict,
secure: process.env.NODE_ENV === "production"
}
}))
FRONT:
import Cookies from "js-cookie";
...
console.log("cookie", Cookies.get("sid"));
I have a cookie named "sid" in this case and I can see it in my console in the browser... but when I try to access it its undefiend
thanks!
Your issue is that you have not set the httpOnly property on the cookie when configuring session. The default value is true which will prevent client browsers from reading the cookie.
Note be careful when setting this to true, as compliant clients will not allow client-side JavaScript to see the cookie in document.cookie.
app.use(session({
name: process.env.SESS_NAME,
resave: false,
saveUninitialized: false,
secret: process.env.SESS_SECRET,
cookie: {
maxAge: parseInt(process.env.SESS_LIFETIME),
sameSite: false, // this may need to be false is you are accessing from another React app
httpOnly: false, // this must be false if you want to access the cookie
secure: process.env.NODE_ENV === "production"
}
}))
See the cookie options in docs