Express Session : terminate session on tab/browser close - node.js

I need to terminate the user session or log user out when they close the browser or tab.
Following is the code implemented to maintain session:
app.use(session({
store: new RedisStore({
url: REDIS_CONNECTION_URL,
}),
secret: 'COOKIE_SECRET',
name: 'COOKIE_NAME',
resave: true,
saveUninitialized: false,
rolling: true,
cookie: {
path: '/',
httpOnly: true,
maxAge: 'COOKIE_TIMEOUT',
},
}));
I have tried setting cookie.expires to true but that doesn't help.

You have to handler onclose event of client user, then call a http request to destroy client's session on server side.
Client side:
$(window).unload(function () {
$.get('/session/destroy');
});
Server side:
app.get('/session/destroy', function(req, res) {
req.session.destroy();
res.status(200).send('ok');
});

Related

Persist expired session data into new session in express js

const adminSession = session({
secret: process.env.ADMIN_SECRET,
resave: false,
saveUninitialized: false,
store: sessionStore,
name: "adminSession",
cookie: {
maxAge: 600000,
secure: false,
},
});
app.use(adminSession());
app.get("/sessionViews", function (req, res, next) {
if (req.session.views) {
req.session.views++;
res.send(`Number of view: ${req.session.vies}`);
} else {
req.session.views = 1;
res.send(" No views");
}
});
Here after the session is expired, req.session.views value is also gone. And new session will be generated with req.session.views=0.
That's how we create the number of views in the certain page, isn't it?
How to keep value persistent with another session?

Express Session lose data before cookie expires

I'm using express-session with redis in my NodeJS Backend.
let redisClient = redis.createClient(6380, process.env.REDISCACHEHOSTNAME, {auth_pass: process.env.REDISCACHEKEY, tls: {servername: process.env.REDISCACHEHOSTNAME}});
app.use(session({
store: new RedisStore({ client: redisClient }),
saveUninitialized: false,
secret: process.env.secret,
resave: true,
cookie: {
maxAge: 1 * 1 * 60 * 60 * 1000
}
}));
On login I store some user details in the session:
req.session.user = result;
And I build a middleware, which log my current session and refresh it on each request:
isOnline = (req, res, next) => {
console.log(req.session);
if (!req.session.user) {
return res.status(401).json({ result: 'Keine Session vorhanden', status: 'failure' });
}
req.session.touch();
next();
};
The extending of my cookie is working well. The cookie expiration datetime is everytime reset to 60 minutes from the request time. Which I can see by the console.log:
Session {
cookie: {
path: '/',
_expires: 2022-03-07T18:46:30.727Z,
originalMaxAge: 120000,
httpOnly: true
},
user: { ... }
}
The issue is, that my user data are lost after 60 minutes. So the cookie itself refreshs, but not the data. So how I can avoid this?

How can I set the domain attribute in express-session based on the request origin?

I'm using express session. I set the domain domain: 'mydomain.com' so that the session cookie can be set between subdomains- like api.mydomain.com and staging.mydomain.com.
But this prevents the Set-Cookie header from setting the cookie when testing with a localhost frontend. I get Set-Cookie was blocked because its Domain attribute was invalid with regards to the current host url.
So I need to make the domain attribute change to localhost if the origin is localhost.
If I conditionally set the domain, we don't have access to req:
app.use(session({
secret: 'very secret 12345',
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
cookie: {
domain:
req.get('origin').slice(0, 17) === 'http://localhost:' ? 'localhost' : 'mydomain.com',
secure: true,
httpOnly: true,
sameSite: none,
},
})
);
This returns ReferenceError: req is not defined.
So I tried calling session in a custom middleware to get access to req:
app.use((req, res, next) =>
session({
secret: 'very secret 12345',
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
cookie: {
domain:
req.get('origin').slice(0, 17) === 'http://localhost:' ? 'localhost' : 'mydomain.com',
secure: true,
httpOnly: true,
sameSite: none,
},
})
);
But it doesn't work. It seems that with this, res, req, and next don't get passed in to the middleware function that session() returns. I also trying calling the function session() that returned -session({..options..})() , but that didn't work either.
How can I set the domain attribute based on the request origin?
I had to call the function and pass in req, res, and next
app.use((req, res, next) =>
session({
secret: 'very secret 12345', // to do, make environment variable for production
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
cookie: {
domain:
req.get('origin').slice(0, 17) === 'http://localhost:' ? 'localhost' : 'mydomain.com',
secure: true,
httpOnly: true,
sameSite: none,
},
},
})(req, res, next)
);

Localhost react app not receiving cookie from Heroku hosted node API

I am able to log in and out with POSTMAN through the heroku hosted node API.
In my react application, the API call with AXIOS (withcredentials:true) does not set the passport cookies, causing the session to not persist. Localhost react and Localhost server does not have this problem.
HEROKU SERVER SIDE, I have the following code:
app.use(cors({
origin: "http://localhost:3000",
credentials: true
}));
app.enable('trust proxy');
mongoose.connect(dbconfig.url, {
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false });
// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded({extended: true}));
app.use(cookieParser('street'));
app.use(session({
secret: 'katsura street',
resave: true,
saveUninitialized: true,
proxy: true,
store: new MongoStore({ mongooseConnection: mongoose.connection },)
}));
app.use(passport.initialize());
app.use(passport.session());
I have checked that the cookie parser is above the session,
the session is initialized before passport.
Is my cors affecting my local reactapp? instead of localhost, am I supposed to reference my local computer's external API?
REACT SIDE:
Axios.post(Config.ServerURL + 'auth/login',
{email: this.state.email, password: this.state.password},
{
withCredentials: true
}).then(result => {
console.log(result.data);
}).catch(error => {
//make sure message doesn't crash
if (error.response !== undefined) {
try {
console.log(error.response);
this.setState({message: error.response.data.info.message})
}catch(error) {
console.log(error);
}
}
});
After checking the headers and seeing that the cookies are sent but filtered out, I came to a article: heroku blog
After 2019, Chrome and other browsers have cross domain cookies disabled to prevent CSRF attacks.
In my use case, I can just turn it off with the following on the Node API server:
app.use(session({
secret: 'street',
resave: true,
saveUninitialized: true,
proxy: true,
cookie: {
sameSite:'none',
secure:true
},
store: new MongoStore({ mongooseConnection: mongoose.connection },)
}));
changing samesite to none, will allow chrome to set your cookies with cross domains.
In my case, it was just setting, in the session settings, cookie.sameSite to "none", and proxy to true.

nodejs session cookie browser storage

Server is nodejs with express-session, passport, express
I want to avoid saving a cookie when the user is not authenticated, is this possible?
var sessionStore = new session.MemoryStore;
app.use(session({
cookie: { maxAge: null,
httpOnly: true,
secure: true,
},
store: sessionStore,
resave: 'false',
secret: 'somthing',
name: "id",
saveUninitialized: false
}));
Is it somehow possible to only store the cookie when the user did successfully login? Thanks!
You have to create an express-session: https://www.npmjs.com/package/express-sessions
and then store the session like this:
let session = require("express-session");
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: true,
cookie: {secure: true,
httpOnly: true,
maxAge: 1000 * 60 * 60 * 24
}
}));
This session will be stored during your visit on the webpage. If you want to set values to the cookie, simply request the cookie in a request and set somekind of value:
router.route("/login")
.post(function(req, res) {
req.session.Auth = req.body.user // => user values?
})
OR
You can use cookie-session(https://www.npmjs.com/package/cookie-session)
If you use cookie session then if you made any changes to session variable or from server side, then no need to restart server.
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2']
}))
app.get('/', function (req, res, next) {
// Update views
req.session.views = (req.session.views || 0) + 1
// Write response
res.end(req.session.views + ' views')
})

Resources