How to hook into express session creation event - javascript

How can I tell when express creates a new session? I'm using a mongodb session store.
I'm having an issue with extra sessions being created, and want to narrow down on the problem by tracking which urls requests are triggering new sessions to be created.

This is what I ended up doing.
app.use(function(req, res, next) {
if (!req.session.returning) {
// session was just created
req.session.returning = true
} else {
// old session
}
next()
})

You can hook into the genid callback. By default express-session generates its own session IDs.
But you can generate the session ID yourself by specifying a genid callback. Within this callback you can log that a new session is being created (and then return a unique session ID).
Here is an example, adapted from the express-session README:
app.use(session({
genid: function(req) {
console.log('New session was created');
return genuuid(); // generate a UUID somehow and return it
},
secret: 'keyboard cat'
}));

The answer by Nate is fine. I'm answering because of 2 additions I'd like to make.
In case you also want the kind of sessionID that express-session would otherwise generate. You can do this:
const uid = require('uid-safe').sync;
//...
genid: function(req) {
console.log('New session was created');
// do what you want to do here!
return uid(24); // <-- the way express-session generates it
},
Be aware that you cannot use an async function for genid. Express-session calls this function without await, so that would get a promise instead of the uid.

Related

NodeJs express-session don´t save the session

I´ve a problem by saving something in the session above a NodeJs Script. If I start the script and making a post login like this:
app.post('/login', function(req, res) {
sess = req.session;
sess.key = "SecureKEy";
console.log(sess);
});
I got as rusult that what I want:
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
key: 'SecureKEy' }
But if I reload the page with this code the session.key is empty. Just like it´s not saved.
app.get('/', function(req, res) {
sess = req.session;
console.log(sess);
res.sendFile(__dirname+'/wwwroot/index.html');
});
My configuration for the express-session is this:
const session = require('express-session');
app.use(session({
secret: 'importent',
resave: true,
saveUninitialized: true
}));
I´ve rewrite the code like this:
app.post('/login', function(req, res) {
console.log("Before: ");
console.log(sess);
sess = req.session;
sess.key = "SecureKEy";
req.session.save();
console.log("After: ");
console.log(sess);
});
With that it work correctly. But if I would resend the logged in page with res.send the session would be automaticly saved? Is that correct?
express-session auto-save edge cases?
The express-session save(...) method is certainly not triggered for some express response transport methods. It seems to trigger consistently for the frequently encountered ones such as response.send(...), response.json(...) etc.
But same is not the case for the special case transport method such as the express.response.end() method - from my observation at least; and also response.sendFile(...) according to the OP and response.redirect(...) according to posts elsewhere.
To avoid unforeseen issue, pay close attention when applying express-session to requests where special case response transport methods were used. The express-session save(...) method may have to be called directly to persist changes made during those requests. Even then, there is no guarantee that persistence would take place.
For example, there are occasions where setting values to null and/or calling the session.destroy(...) and/or session.regenerate(...) methods have no effect. Those destructed session data basically resurface on the next page refresh. Not even calling the save(...) method or setting the unset option to 'destroy' can remedy that situation.
The express-session readme should include these edge case scenarios in one of its Note sections at the top of the page. It would curb some of the headwinds surrounding its auto-save feature.
My philosophy to this type of thing is: when a package is too quirky for a use-case, either find a more suited package or just source your own solution if possible. Workarounds tend to warp application logic thereby making it error prone and difficult to maintain over time.

Get the current user outside of a route using Passport.js

I am using the latest version of Express (4.x) and Passport.js (0.13) in my Node.js application. I can get the current user object inside of a route by using req.user and working with the object, which works. However, for situations outside of routing, is there a method I can call or global object I can access which contains the same information?
The reason I want to do this is I have a Socket.io listener which waits for a message string to be sent. It then gets the currently logged in user, gets their ID and uses that for the database association. This takes place outside of a route obviously.
Passport.js uses session to deserialize the user and have it store at express.js req object. So to authenticate the user in Socket.io, you need to find the session using the cookie, lookup the session in the session store and finally get the user from the session.
You can use Socket.io middlewares to achieve this. Here is a pseudo-code to get you started:
var io = require('socket.io')();
io.use( (socket, next) => {
if (socket.request.headers.cookie) {
// find the session id in cookie
const sessionID = socket.request.headers.cookie['connect.sid']
// lookup the sessionID in session store
MongoStore.get(sessionID, (err, session) => {
// get the userID from the session
const userID = session.passport.user;
// Lookup user using the UserID
User.find(userID, (err, user) => {
//save the user in socket
socket.user = user;
next();
})
})
}
next(new Error('Authentication error'));
});

Get Session Variable in middleware function in express js

I am working on a website with the help of express.js and mongodb.
To use this website persistently I am using express-session v1.11.3. And, to check if a user is logged in or not, I have created a middleware function. In this function I am trying to get a session but it always returns Undefined.
When login to the router, I have an initialized session variable with user obj. as below:
//users router
router.all('/login', function(req, res) {
var db = req.db;
.....
........
//on successfully login
req.session.user = user;
res.redirect('/dashboard');
});
After I created this middleware function in the users.js router file to authenticate. Here is the code of this function:
function requiredAuthentication(req, res, next) {
if (req.session.user) {
next();
} else {
res.redirect("/users/login");
}
}
Now, I am trying to get users listing and only authenicated users get this:
router.get('/index',requiredAuthentication, function(req, res, next) {
var db = req.db;
db.collection('users').find().toArray(function(err, users) {
if (err) {
res.render('error', {error: err});
}else {
res.render('users/index', {users: users});
}
});
});
But it's not working properly.
The code parts that you've posted seems ok, the problem might be in other code that is not visible here.
First of all make sure that you've assigned the req.session.user correctly, inside the asynchronous callback where user is fetched from the db.
Also check whether the express-session middleware is included properly, don't forget to use(session) middleware, like:
var express = require('express');
var session = require('express-session');
var app = express();
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}));
Also, try to include and use(express-cookies) middleware, this was an issue in previous express versions, but now it's used automatically by express-session.
a good practice would be to also check if a session exists before you check if a user is added to a session var.
if (req.session && req.session.user) {
//do something
}
that could also indicate more on where the problem lays.
also . try putting the function in the controller and see if it still doesn't work for you. (instead of passing it in the route)
check to see if you correctly applied all the modules needed (express-session - and is up to date and not corrupted. (update to latest version if no)
make sure your middleware is set correctly
app.use(session({
secret: '',
saveUninitialized: true/false,
resave: true/false
}));
if you did checked all of the above, take a look at the console of your server. does it output any error regarding the session var or decleration.? if so please post
hope this guide you somehow. cheers

Passport for authentication in Node JS

I am considering using the Passport Library (http://passportjs.org/) for authentication in a Node project.
I am confused by the following passport session functions:
passport.serializeUser(function( user, done ) {
done( null, user.id );
});
passport.deserializeUser(function( id, done ) {
user.get( id, function ( err, user ) {
done( err, user );
});
});
I am wondering:
1) Do these get called for every request that needs to be authenticated? Or are they just called once when the session is first created?
2) How do I access the information that is in "user" from other parts of my script?
3) For requests that need to be authenticated, where do I put any additional logic. eg To check if an allowable user idletime value has not been reached.
Thanks (in advance) for your help
1) serializeUser is called when creating a session for the user (when authentication was successful). This is used to store some sort of identifying information (like a unique user-id) about the user in an Express session.
deserializeUser is called for every request, and takes that piece of identifying information from the session to somehow convert it back to a full user record by means of a database query, perhaps, but that's really up to you: instead of just storing the user id you could also store the entire user record in the session, but it depends on the type of user record and the session storage you're using if that's possible (for example, using express.cookieSession would limit the amount of data you can store in a session).
This is what storing the entire user record could look like:
passport.serializeUser(function(user, done) {
// Here, 'user' is the result of the function called by 'new LocalStrategy()'; when
// you call done() below, that result will be stored in the session.
done(null, user);
});
passport.deserializeUser(function(user, done) {
// Here, 'user' is what's stored in the session by serializeUser()
done(null, user);
});
2) Passport populates req.user which you can use in routes or middleware.
3) You could make a middleware to implement such checks. This might be a good starting point.

Express session not persisting

I'm trying to set up a basic session system in node. Here's what I've got so far:
app.js:
app.use(express.cookieParser('stackoverflow'));
app.use(express.session());
I'm setting the session data in ajax.js:
addClassToCart: function(req, res) {
req.session.cart = req.body.classId;
console.log(req.session.cart);
}
This logs the correct information. However, when I try to retrieve that information elsewhere (same file, different function):
console.log(req.session.cart);
I get undefined. I feel like I'm missing something incredibly basic. Various tutorials for this are either awful or require me to add in even more packages (something I'm trying to avoid).
More data from my debugging:
This works with non-AJAX requests
The session is set before it's logged.
As it turns out, the issue wasn't with Express' session (as the other answers seem to think). Rather, it was a misunderstanding on my part. I changed addClassToCart to the following:
addClassToCart: function(req, res) {
req.session.cart = req.body.classId;
console.log(req.session.cart);
res.send('class added');
}
Adding res.send() fixed the problem.
As noted in the answer to a related SO question, this can also occur if you're using fetch to get data from your server but you don't pass in the credentials option:
fetch('/addclasstocart', {
method: 'POST',
credentials: 'same-origin' // <- this is mandatory to deal with cookies
})
Cookies won't be passed to the server unless you include this option which means the request's session object will be reset with each new call.
I don't know about basic session store, but redis only took me a few minutes to setup:
app.use(express.session({
store: new RedisStore({
host: cfg.redis.host,
db: cfg.redis.db
}),
secret: 'poopy pants'
}));
On a mac:
brew install redis
app.use(express.session({
secret: "my secret",
store: new RedisStore,
cookie: { secure: false, maxAge:86400000 }
}));
Not sure the problem is in session age, but it just to be safe, I'd suggest you to specify maxAge.

Categories