express cookie-session failing on mobile - node.js

I am trying to use cookie-session in express / nodejs, my setup works on PCs, but not on mobile:
on Android/Firefox, I can setup the session cookie, but I cannot modify it once set, I can't event erase it by setting req.session=null. Android/chrome is fine.
on iOS (Safari, chrome, firefox), the cookie doesn't seem to ever be set (iOS 15.3).
The setup is as follows:
my website is hosted at "mywebsite.com" (names modified for this forum)
my API setting/using the cookie is at another URL "mywebsite.io" (different extension)
cookie-session options are:
name: 'session',
keys: ['my secret'],
sameSite: 'none',
secure: true,
httpOnly: true,
signed: true,
overwrite: true,
Both website and API implement https. The API is behind a nginx proxy. Express includes this:
app.set('trust proxy', 1); // trust first proxy
to make sure the secure option works behind the proxy.
The web client is created in React, I run API calls using superagent with the .withCredentials() option.
I have tried:
setting the maxAge option
setting the domain option to 'mywebsite.io' or 'mywebsite.com'
setting the 'path' option to '/'
using the should-send-same-site-none module
Whatever I do, the iOS cookie is always empty (req.session = undefined on subsequent calls), and the Android/Firefox combo wont't let me update it.

Related

node.js express session access token doesn't persist after changes

I'm quite new to OAuth and not sure what to do with the access token I receive from another party. Right now I'm using express session on https with secure and httpOnly settings. This works fine, until I upload an image on the same API server (which happens after I add a product). Everytime my server detects changes, the token I saved becomes undefined, this means that the user has to go through the whole OAuth process again.
Since I use MYSQL, is it possible to save the token information in the database (expiry, refreshtoken, accesstoken) linked to the user or is there a better way to save this data?
My setup is very basic, I have one API Server and one React app for front-end.
I receive the token information by making an API call with my own API to the other party, the response from this party is what I end up sending as cookies to the React app.
This is the session code I have right now:
app.use(
session({
secret: process.env.SESSION_SECRET,
name: "token",
cookie: {
secure: true,
httpOnly: true,
},
resave: true,
saveUninitialized: true,
})
);
For anyone that runs into the same problem, by default express session uses MemoryStore. I missed this when I was reading the documentation.
MemoryStore is purposely not designed for a production environment. It
will leak memory under most conditions, does not scale past a single
process, and is meant for debugging and developing.
To fix this, you can use either "cookie-session" or pick one of the stores from the documentation.
https://www.npmjs.com/package/express-session#compatible-session-stores

Secure cookies option in Express - how to access

In a node app, I want to use cookies to read data. If I want to make a cookie using the options:
res.cookie('user', '123', { signed: true, httpOnly: true, secure: true }
and later read the cookie in a node endpoint/controller:
router.get('/test', testHandler)
function testHandler(req, res){
// how to read the secure cookie here?
}
how can I access this secure cookie on my local machine? Would I have to set up an https server locally to be able to read it?
You can just do req.session
Remember if you set the secure attribute to true, the connection has to be made over HTTPS, otherwise it won't work.

Unable to get session cookie using axios and Express Session. But able to with Postman

I have been able to find countless topics of discussion on this, but none of the solutions seem to work for me
Essentially, I have a react client that uses axios to make requests to a node js backend which uses express session
I’m able to log into the application and get a successful response. However, the response header does not include the connect.sid field. And when checking chromes devtools -> application -> cookies folder, I don’t see any cookies there for the site
I also tried testing this using IE and Firefox with the same result
Now when making the same login request via postman, I’m able to see both the connect.sid in the header and the cookie itself in the cookies tab.
In my current situation, the client and server are both running on localhost, with the client running on port 3000 and the server running on port 3001. One difference is that client is http and server is https
From my research online, these are the common things suggested, with neither working in my case
Setting axios withCredential to “true” in react. This appears to have fixed the problem for majority of the people online. I have mine set up as well
import axios from "axios";
axios.defaults.withCredentials = true;
Setting the httpOnly field to false for the session cookie in the server. Below is my session configuration
app.use(session({
secret: 'BSL3562904BVAIHBP53VRFSF',
resave: false,
saveUninitialized: false,
rolling: true,
cookie: {secure: true, httpOnly: false }
}))
Configuring the cors settings in the server. This shouldn’t affect me in this scenario as the client and server are running on the same domain, but I still covered that base anyway
app.use(cors({
credentials: true,
origin: "http://localhost:3000"
}));
For the origin value I tried both “localhost” and “127.0.0.1”
Setting “trust proxy” in server
app.set('trust proxy', 1);// trust first proxy
This isn’t simply an issue of not being able to retrieve cookies in the client, as I can create and attach cookies to the response and see them. It’s just the session cookie that does not appear
At this point, I’m kind of banging my head against a wall. So any help or suggestions would be much appreciated!

Express session-cookie not being sent on openshift with https and secure flag

Got a strange issue, I am using Express and in development we use http and have secure: false for the session cookie, however now we are moving to openshift we have turned https on thinking it would be a simple endeavour but our cookies are not being sent back with the responses. If however we turn off https and revert back to http on openshift it works fine and cookies are sent.
So here is an example of what the cookie config looks like:
var setupSession = function() {
var sessionConfig = {
secret: environmentVars.cookie.secret,
name: environmentVars.cookie.name,
maxAge: environmentVars.cookie.expiry,
domain: environmentVars.cookie.domain,
httpOnly: true,
secure: environmentVars.cookie.secure, // true when using https
secureProxy: environmentVars.cookie.secure, // true when using https
signed: true
};
app.set('trust proxy', 1); // Just added this, still no luck
app.use(session(sessionConfig));
};
So the above is run when the app starts up and as noted in the comments when we are using a secure connection the environment vars are set for us, and when the above is used in conjunction with HTTPS no cookie is sent back from express, however openshift cookies are sent back, like the gears one etc. Again with http and disabling the secure stuff it works fine we all get cookies and rejoice. All responses work and data is sent back its just the set-cookie header is missing for the apps cookies (but as mentioned not openshift ones).
So the actual certificate is not setup within nodejs it is setup on openshift as an alias with a certificate applied. So express really has no idea it is being run in https other than the environmental vars it is passed and the port it is provided by the gear that is running it.
So has anyone else had anything similar or has any ideas on what we can try to solve the problem or diagnose it? I did some reading and people suggested trying the trust proxy and secureProxy, which has been done but still no luck.
So it turns out I was just being an idiot, it should look like:
var setupSession = function() {
var sessionConfig = {
secret: environmentVars.cookie.secret,
name: environmentVars.cookie.name,
maxAge: environmentVars.cookie.expiry,
domain: environmentVars.cookie.domain,
httpOnly: true,
secureProxy: environmentVars.cookie.secure, // true when using https
signed: true,
cookie: {
secure: environmentVars.cookie.secure, // true when using https
}
};
app.set('trust proxy', 1); // Just added this, still no luck
app.use(session(sessionConfig));
};
All works now :)
I had similar problem with express-session and after many trials the culprit for me was setting cookie.domain. Browsers wouldn't save the cookie.
This is how I was setting the value:
cookie: {
...
domain: process.env.OPENSHIFT_CLOUD_DOMAIN,
...
}
Hope it helps anyone going through the same, since at the time this is the best suited stackoverflow question to share this.

Server to server authentication with Node.js, Passport

I have two services running on different sub-domains: 1) Node.js, Express, PassportJS, 2) PHP based. Both services are exposed in same portal, in order to avoid requiring user to enter credentials twice, we call Node.js login API from PHP server. Node returns session cookie (connect.sid), we forward this to client with domain set to <<rootdomain>>.com. Now when client calls Node.js, we can see cookie being sent to Node but still Node fails to authenticate.
I have verified following things:
Login API call from PHP server to Node returns success with connect.sid cookie and adds session entry into Redis server (We are using Redis for storing sessions)
Cookie is set correctly in browser
When browser calls Node.js connect.sid cookie is sent to server
If we call login API directly from client, everything works as expected. Basically stand alone Node app works without any issues.
I am curious whether Node uses User-agent, IP or something to validate connect.sid cookie? Or is it something related to Passport/Express session params values? What might be wrong? FYI, currently site is not running on SSL.
Here are my session params:
store = new RedisStore({
port: 6379,
host: 'localhost',
client : redis
});
var sess = {
store: store,
secret: 'some secret',
rolling: true,
cookie: { maxAge : 36000000, secure: false },
saveUninitialized: true,
resave: true,
sortName: 0,
sortModified:0,
sortSize: 0
};
Thanks in advance

Resources