I know this question is redundant, but I have been searching and reading articles all around for hours now. I am using express-session to control user sessions for the express server. It works when I try to console req.session.user from a postman request. When I try to fire the same request from the browser, it returns undefined. Everyone is talking about Chrome security updates and third-party cookies restrictions. I've tried to stick to chrome guidelines on cookie options but didn't help. If I deployed my client or server to a secure domain would it help?
Here are my options
app.use(cors())
app.set('trust proxy', 1) // trust first proxy
app.use(session({
store: new (require('connect-pg-simple')(session))({pool}),
secret: process.env.SESSION_SECRET,
resave: true,
rolling: true,
cookie: {
maxAge: 30 * 60 * 1000, // 30 minutes
secure: false,
sameSite: 'none'
},
saveUninitialized: false,
}));
Related
I've looked through quite a few issues on this and have tried every combination of "solutions" for my problem but can't seem to figure this one out.
I currently have a client side react application being hosted on azure. Let's call this https://clientside.net for short.
I also have a server side node js application being hosted on azure we'll call this https://serverside.net.
I can't seem to to get the session variables to save upon authenticating users. This works perfectly fine on localhost btw.
e.g. On the client side we are making requests using axios like so:
const headers = {
withCredentials: true,
headers: { auth: process.env.REACT_APP_SECRET },
};
axios.get(`${process.env.REACT_APP_SERVER}/get/auth`, headers).then((response) => console.log("blah blah blah"));
On the server side this is how express session is setup...
app.use(
cors({
origin: ["https://clientside.net"],
methods: ["GET", "POST"],
credentials: true,
})
);
app.set("trust proxy", 1);
app.use(
session({
name: "sid",
saveUninitialized: false,
resave: false,
secret: "shhh",
cookie: {
domain: ".clientside.net",
maxAge: 1000 * 60 * 60 * 8,
secure: true,
httpOnly: false,
},
})
);
Within our authentication route on server side we are saving session like so ...
req.session.username = req.body.username;
req.session.password = req.body.password;
req.session.save(() =>
res
.status(202)
.json({
authenticated: true, username: req.session.username})
);
Upon refreshing or attempting to hit any other routes, the req.session.username & req.session.password are nowhere to be found. Is there something wrong with my session config? Or am I perhaps missing something? I appreciate any and all help on this! Thanks y'all
I've figure out the issue.
Deploying an application using azure app services, means you will be using a reverse proxy.
In my case nodeiis web service proxy.
The client side makes requests to the iis service which then routes the request to the node server.
I made many changes but the one that got me up and running was switching the cors origin and session domain to be the server side domain/ip like so...
app.use(
cors({
origin: ["https://serverside.net"],
methods: ["GET", "POST"],
credentials: true,
})
);
app.set("trust proxy", 1);
app.use(
session({
name: "sid",
saveUninitialized: false,
resave: false,
secret: "shhh",
cookie: {
domain: ".serverside.net",
maxAge: 1000 * 60 * 60 * 8,
secure: true,
httpOnly: false,
},
})
);
Now session variables are able to be successfully saved upon login.
I have a simple requirement to store an access token/refresh token in Express (without using localStorage or anything). I'd like to store them in a persistent httpOnly cookie so any time a user visits the page who has previously visited the page can see if the access token is already there, and if so, make API calls and log in and so on.
I've spend some time looking at express-session and cookie-session and simply can't figure out the proper way to do it. express-session requires a store for production, and I don't want to set up a store to simply store an access token. So something like this works in devleopment:
app.use(
session({
secret: 'conduit',
cookie: {
path: '/',
maxAge: 60 * 60 * 1000,
httpOnly: true,
secure: isProduction,
},
resave: false,
saveUninitialized: false,
})
)
Using this to set it on request:
request.session.accessToken = accessToken
request.session.save()
But if it's not going to work in a production environment, it's not helpful. I haven't been able to get it working with cookie-session, or I don't know how to set/retrieve the cookies, and the documentation isn't very helpful.
So I'm asking: how can I store a few strings on an Express server/httpOnly cookie in a persistent way, without using a Store/Redis/MemCache/etc?
I had to use cookieParser.
const cookieParser = require('cookie-parser')
app.use(cookieParser())
// set a cookie
response.cookie('nameOfCookie', 'cookieValue', {
maxAge: 60 * 60 * 1000, // 1 hour
httpOnly: true,
secure: isProduction,
})
// get a cookie
request.cookies.nameOfCookie
// destroy cookie
response.clearCookie('nameOfCookie')
Why does this work:
router.use(session({
name: process.env.SESSION_COOKIE,
genid: () => uuidv4(),
cookie: {
httpOnly: true,
},
secret: process.env.SESSION_SECRET,
store: new RedisStore({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
ttl: 1 * 24 * 60 * 60, // In seconds
}),
saveUninitialized: false,
resave: false,
}));
But this doesn't?
router.use(session({
name: process.env.SESSION_COOKIE,
genid: () => uuidv4(),
cookie: {
httpOnly: true,
secure: true,
},
secret: process.env.SESSION_SECRET,
store: new RedisStore({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
ttl: 1 * 24 * 60 * 60, // In seconds
}),
saveUninitialized: false,
resave: false,
}));
Setting secure to true results in the session cookie not being set at all. FWIW, I'm using PassportJS for authentication.
NOTE: This question might look similar to this one but the top-voted answer there doesn't quite address the issue. It says httpOnly is causing the problem but I don't understand why it would? The cookie isn't being set on the client, right?
The file in question is up at https://github.com/amitschandillia/proost/blob/master/web/routes/auth-routes.js.
NOTE 2: The server is SSL-enabled and the URL is https://www.schandillia.com.
The secure option for a cookie means that the cookie is ONLY sent by the browser over an https connection and, in some browsers, the cookie marked as "secure" won't even be saved by the browser for future requests if it arrives over an insecure connection.
Your server appears to be an http server so the cookie will not be sent back to your server on subsequent requests making the cookie disappear.
In Expressjs, i have some code to use cookie session, which is a middleware that is like express-session, but it keeps the session even after the server restarts. I was looking at other questions, but they all said that you should add a maxAge attr to the cookie. I did this, and the session still expires after the browser closes. Here:
const express = require('express');
const app = express();
const session = require('cookie-session');
app.use(session({
name: 'session',
secret: `secret`,
httpOnly: true,
expires: new Date(Date.now() + 999999999999999999999999999999999999999999999999999999999999999999999999999*9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999*999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999),
maxAge: 999999999999999999999999999999999999999999999999999999999999999999999999999*9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999*999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999,
signed: true
}));
This is was shown in other questions, (besides the expires and maxAge being very long). So, what is my problem? Again, i would like to make the session last even after the window closes, right now it lasts after the tab closes but not the entire window. This only needs to work in Chrome. Thanks!
You can try:
app.use(session({
secret: "session",
resave: true,
resave: false,
saveUninitialized: true,
key: 'express.sid'
}));
Otherwise, I would save the cookie to database, and always compare user's cookie with cookies in db.
P.S.
Note If both expires and maxAge are set in the options, then the last one defined in the object is what is used.
source: https://www.npmjs.com/package/express-session
My app is divided between Client and Server. Client is a frontend side Nextjs app hosted on Now.sh, Server is its backend created with Express and hosted on Heroku, so the domains are client-app.now.sh and server-app.herokuapp.com .
Authentication
Authentication system is based on cookies and I'm using express-session to achieve it. This is my express-session configuration
app.use(
session({
store:
process.env.NODE_ENV === "production"
? new RedisStore({
url: process.env.REDIS_URL
})
: new RedisStore({
host: "localhost",
port: 6379,
client
}),
name: "sessionID",
resave: false,
saveUninitialized: false,
secret: keys.SESSION,
unset: "destroy",
cookie: {
domain:
process.env.NODE_ENV === "production"
? ".client-app.now.sh"
: "localhost",
secure: process.env.NODE_ENV === "production",
httpOnly: true,
maxAge: 7 * 24 * 60 * 60 * 1000
}
})
);
Cors is set with the "cors" package:
app.use(
cors({
origin:
process.env.NODE_ENV === "production"
? process.env.CLIENT_URL
: "http://localhost:3000",
credentials: true
})
);
Client is configured with Apollo and "credentials" in HttpLink is set to "include".
The problem is that cookie with session ID is correctly set in development, but not in production. Could this be related to the fact that I'm hosting client and server on different domains?
I had my production node server behind a reverse proxy. This causes node to not trust the proxy and thus not set cookies.
I had to enable trusting the first proxy when in production.
app.set('trust proxy', 1) // trust first proxy
More info check out express-session's docs on the topic.
After a lot of time trying to solve this, I just found the solution:
So I had,
app.use(session({
secret: secret,
saveUninitialized: false,
resave: false,
cookie: {
domain: clientDomain,
secure: true
}
}));
I removed all the cookie object and this solved my issue:
app.use(session({
secret: secret,
saveUninitialized: false,
resave: false
}));
Browsers seems don't need help to get the cookies.