express-session - req.session not showing saved session - node.js

I am not able to view req.session saved data after storing userId after user logs in.
When I console.log the session from the login function I get the proper data...
Session {
cookie:
{ path: '/',
_expires: 2019-02-23T12:17:24.134Z,
originalMaxAge: 7200000,
httpOnly: true,
sameSite: true,
secure: false },
userId: 4 }
But when I console.log(req.session) from other routes after that I get a new blank session
Session {
cookie:
{ path: '/',
_expires: 2019-02-23T12:12:47.282Z,
originalMaxAge: 7200000,
httpOnly: true,
sameSite: false,
secure: false } }
I am working on my localhost using React frontend on port 3000 and Node/Express with express-session and redis-connect. When I view my Redis I see the stored session properly.
This is my session code...
app.use(
session({
store,
name: 'sid',
saveUninitialized: false,
resave: false,
secret: 'secret',
cookie: {
maxAge: 1000 * 60 * 60 * 2,
sameSite: true,
secure: false
}
})
)
I have tried all different values for these options and nothing works. Please help!

The answer came from a mix of answers from RobertB4 https://github.com/expressjs/session/issues/374
Apparently this problem is common when using CORS middleware and fetch api. In all of your fetch calls you need to send a credentials property set to 'include' and in your cors middleware you need to set an option to credentials: true. It is not good enough to do one or the other, you must do both...
fetch('url', {
credentials: 'include'
})
const corsOptions = {
credentials: true
}

Related

Express-session store is not returning the full session object with custom data

I've been working on this problem for a while, and I am stumped.
I am using express-session with connect-redis as a store for the sessions. I am using typescript.
I added this to the top of my server file and I am able to access the fields without any typescript errors.
declare module "express-session" {
interface SessionData {
userId: string;
role: UserRole;
}
}
When I log a user in, I set the extra SessionData fields.
request.session.userId = user._id.toHexString();
request.session.role = user.role;
console.log(request.session);
Via Postman, I can see that the cookie is set and returned. Additionally, I checked Redis for the session key and the session is correct. e.g.
{\"cookie\":{\"originalMaxAge\":604800000,\"expires\":\"2023-01-23T17:34:05.158Z\",\"secure\":true,\"httpOnly\":true,\"path\":\"/\"},\"userId\":\"1234\",\"role\":\"userRole\"}
However, the extra fields I added to SessionData are not being populated after calling the session middleware. Instead of getting:
Session {
cookie: {
path: '/',
_expires: 2023-01-23T17:52:49.153Z,
originalMaxAge: 604800000,
httpOnly: true,
secure: true
},
userId: '1234',
role: 'userRole'
}
I get:
Session {
cookie: {
path: '/',
_expires: 2023-01-23T17:52:52.339Z,
originalMaxAge: 604800000,
httpOnly: true,
secure: true
}
}
This is how I am calling the session middleware:
const sessionOptions: SessionOptions = {
secret: "secret key",
resave: true,
saveUninitialized: true,
cookie: { secure: true, httpOnly: true },
store: store,
};
app.use(session(sessionOptions));
I thought it may have been an issue with redis, but the key/value is being persisted. I thought maybe it was an issue with connect-redis, so I used the default MemoryStore, but that doesn't work either.
Any help would be appreciated!
Of course right after I ask this question I figure out what the answer is...
First, don't manually set the cookie for the session id in the response. It will automatically be done for you.
Second, ensure that secure is FALSE on localhost.

Express doesn't set-cookie when SameSite is none

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

Why can't I set cookies over HTTPS?

I have a server that has its own domain and is using HTTPS. I have a website that has its own domain and is using HTTPS as well.
On the home page of the website, there is a login button and a sign up button. Both buttons lead to forms to execute their respective tasks, and both forms send requests to the server that respond with cookies, or at least that's what they are supposed to do.
I am using express-session in combination with Redis to store the session ids. Here is the config for that (connectToRedis is simply a function that returns a RedisClient):
const RedisStore = connectRedis(session);
const redisClient = await connectToRedis();
app.use(
session({
store: new RedisStore({
client: redisClient,
}),
cookie: {
httpOnly: true,
secure: true,
sameSite: "lax",
maxAge: TEN_YEARS,
},
resave: false,
saveUninitialized: false,
secret: SECRET,
name: AUTH_COOKIE,
})
);
For some reason the cookies are not being sent in the requests. The Set-Cookie header isn't even showing up! I tried changing SameSite to none (article), but that didn't work.
This is my first time deploying a production website, so all this HTTPS stuff is kind of new to me.
Thanks for your help, and if you need any extra information, please let me know.
IMPORTANT UPDATE:
Finally, I have made some progress (all it took was a pizza break).
I added the path key to my cookie config and gave it the value of /. I also set proxy to true.
So now it looks like this:
const RedisStore = connectRedis(session);
const redisClient = await connectToRedis();
app.use(
session({
store: new RedisStore({
client: redisClient,
}),
cookie: {
httpOnly: true,
secure: true,
sameSite: "none",
maxAge: TEN_YEARS,
path: "/",
},
resave: false,
saveUninitialized: false,
secret: SECRET,
name: AUTH_COOKIE,
proxy: true,
})
);
With this, the cookie is finally appearing in the requests, but it isn't being set in the browser...

I can't set the SameSite attribute of the cookie to None in Nodejs (Express)

We are creating a backend for a Twitter view app in Nodejs (Express).
I'm thinking of using Twitter Api for login and storing the token returned after authentication to the session and then restoring the session from the cookie when it is accessed again.
However, the cookie is blocked when it is accessed again and I can't restore the session information.
The browser I use is chrome, but since chrome version 80, SameSite attribute seems to be Lax (sends a cookie when called from the site of the same domain) when the SameSite attribute is not specified, and in this case, front and back end are different domains, so cookies are blocked.
So I am trying to set the SameSite attribute to None (sends a cookie when called by any site), but I can't seem to set it well and asked this question.
I'm wondering if I can set the SameSite attribute to None if I make a difference in the part of app.use(session({})), but...
If anyone knows of a solution, I would appreciate your help.
Thank you for your help.
The corresponding source code
callback_url = env.URL + "oauth/callback";
app.use(
cookieSession({
name: "session",
keys: ["thisappisawesome"],
maxAge: 24 * 60 * 60 * 100
})
);
app.use(cookieParser());
// Save to session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// Restore from Session
passport.deserializeUser(function(user, done) {
done(null, user);
});
passport.use(
new TwitterStrategy({
consumerKey: env.TWITTER_CONSUMER_KEY,
consumerSecret: env.TWITTER_CONSUMER_SECRET,
callbackURL: callback_url
},
async (token, tokenSecret, profile, done) => {
return done(null, profile);
}
));
app.use(session({
allowedHeaders: ['sessionId', 'Content-Type'],
exposedHeaders: ['sessionId'],
secret: 'reply-analyzer',
resave: false,
saveUninitialized: false
}));
var cors_set = {
origin: env.CORS_ORIGIN_URL,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true // allow session cookie from browser to pass through
};
app.use(passport.initialize());
app.use(passport.session());
app.use(cors(cors_set));
What I've tried.
1.I tried setting the cookie options in the app.use(session({})) part, but it was not possible to set the SameSite attribute to None.
app.use(session({
allowedHeaders: ['sessionId', 'Content-Type'],
exposedHeaders: ['sessionId'],
secret: 'reply-analyzer',
resave: false,
saveUninitialized: false,
cookie : {
secure: true,
sameSite: 'None'
}
}));
2.I tried using the following middleware (express-samesite-default), but the SameSite attribute can be set to None, and the It wasn't.
var sameSiteCookieMiddleware = require("express-samesite-default");
app.use(sameSiteCookieMiddleware.sameSiteCookieMiddleware());
Additional information
Node.js v12.18.2
chrome v84.0.4147.135
I was able to self-resolve and will describe how I was able to solve the problem.
In the code there are two sessions and a cookie session, but I decided to use the cookie session as it seems to work fine.
The end result is the following
var cookieSession = require("cookie-session");
app.set('trust proxy', 1)
app.use(
cookieSession({
name: "__session",
keys: ["key1"],
maxAge: 24 * 60 * 60 * 100,
secure: true,
httpOnly: true,
sameSite: 'none'
})
);
Hey I just used like this. And it worked. I'm using localhost for both frontend and express backend.
res.cookie('token', token, {
expires: new Date(Date.now() + (3600 * 1000 * 24 * 180 * 1)),
httpOnly: true,
sameSite: "none",
secure: "false",
});
try SameSite: 'none' with capital S it worked for me but i used express-session with cookie-parser... i think your code not working because of small s, when i change my to sameSite it's not working for me too, but SameSite works just as expected
also i use npm i cors
here is my piece of code
app.use(session({
key: 'session_cookie_user_auth',
secret: 'mooncore',
store: sessionStore,
resave: false,
saveUninitialized: false,
cookie: {
SameSite: 'none',
maxAge: 1000 * 60 * 60 * 60
}
}));

Axios isn't sending session data

I've developed an app using React, Mongodb, Node, and Express and i'm using sessions for authentication. On the backend, I can successfully set a cookie a store a userID however when I try to make requests from the react app using axios, the userID session data is not sent.
This is my session config on the backend:
app.use(session({
name: SESS_NAME || "***",
secret: SESS_SECRET || "***",
saveUninitialized: false,
resave: false,
store: new MongoStore({
mongooseConnection: db,
collection: 'session',
ttl: parseInt(SESS_LIFETIME) / 1000 || (60 * 60 * 48) / 1000
}),
cookie: {
sameSite: true,
path: '/',
domain: APP_DOMAIN || 'localhost:4000',
secure: false, //NODE_ENV === 'production',
maxAge: parseInt(SESS_LIFETIME) || 60 * 60 * 48
}
}));
My cors is configured as follows:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:4000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Credentials", true);
next();
});
const corsConfig = {
origin:['http://localhost:3000', 'http://localhost:4000' ],
methods:['GET','POST'],
credentials: true,
};
app.use(cors(corsConfig));
after logging in I set the userID in my user Routes, which I confirmed is set by console logging:
req.session.userId = user._id;
This is an example request from my react app
axios.get('/user/auth', { withCredentials: true })
.then(response => {
...
Note that my app is being served on the same domain - I'm using the node app to serve the react app. my folder structure is similar to the following
- APP PARENT FOLDER
-CLIENT //Whole react app
-MODELS
-ROUTES
-SERVER.JS
-PACKAGE.JSON
-NODE_MODULES
I have searched everywhere and tried everything I can think of... no luck. I would appreciate any help!
I've already checked articles on stack overflow and tried to implement the fixes but have had no luck. I've tried the following fixes:
// in my index.js file
axios.defaults.withCredentials = true;
and adding
{ withCredentials: true }
to all of my requests
When I take the userid created at login (ex: 5d6b5d2b09f7d1332543ba90) and manually plug this into the user Route on the backend then everything works fine.
When I console log the session on every request made by the react app it looks like this:
Session {
cookie:
{ path: '/',
_expires: 2019-09-05T05:38:09.657Z,
originalMaxAge: 172800,
httpOnly: true,
sameSite: true,
domain: 'localhost:4000',
secure: false },
}
When it should look like this:
Session {
cookie:
{ path: '/',
_expires: 2019-09-05T05:38:09.657Z,
originalMaxAge: 172800,
httpOnly: true,
sameSite: true,
domain: 'localhost:4000',
secure: false },
userId: 5d6b5c2b03f7d5532543ba90 }

Resources