Create session only after successful authentication in express - node.js

I have a requirement to create a session only after successful authentication.
I was able to create redisStore based session using express middleware, but it creates session when the first request comes to server.
But how I can create session only after successful authentication.
I googled somewhat, and foundreq.session.regenerate() (but I found the issue as below mentioned in this thread:
Regenerate session IDs with Nodejs Connect)
But in regenerate case also, it creates a fresh one, assuming old one is created already, and is created with same parameter.
So there is any other way to create a new session ID only after successful authentication..?

You may be conflating the idea of a session with the idea of an authenticated session.
It's normal for all users to have a session - even the anonymous, not-yet-logged-in users. The difference between this and an authenticated session is just that, locally on your web server, you specify that a particular user has been authenticated.
For example, once you authenticate someone, you can set:
req.session.isAuthenticated = true;
Then, when rendering pages, your controllers can do something like
function(req, res, next) {
if (!req.session.isAuthenticated) return res.redirect('/login');
res.render('appPage');
}

This might not be the exact answer you're looking for, but I'll answer the title for future readers:
From experimenting with my application, I've noticed that express-session sets the session cookie only if you manipulate the session object.
For example consider the below code:
app.post('/login', function (req, res) {
var authenticated = false;
if (req.session.authenticated) {
// session cookie is already set
authenticated = true;
} else if (/*validate the user here*/) {
console.log(' authenticating');
authenticated = true;
// if below line executes, the response will have Set-Cookie header
req.session.authenticated = authenticated;
}
res.json({
status: authenticated
//if --^ false, no session cookie will be set since we didn't manipulate session object
});
});
Even though a request creates a session object in memory for us to use, the Set-Cookie header seems to be sent only if we manipulate (or tamper with?) the session object created.
Unless we sent the Set-Cookie header along with the response and session id is stored in cookie at client side, I wouldn't consider it as an established session and worry about it.
Hope it helps.
Side note: This is the case of a cross-domain ajax request, might be different for normal http request, perhaps someone can confirm this

Related

Why use cookie-session in addition to passport.js?

My understanding of passport.js so far is that passport.js serializes the user object and sends an ID every time to the client. I am just starting with it so sorry if it's a silly question:
Instead of express-session, I am using cookie-session as I am a beginner. My understanding of cookie-session is that it sends a session ID every time, and this ID can be used to look up the database when needed.
Now, I don't understand why we can't just use the passport.js ID? Why do we need to use cookie-session in addition? Also, (this may be a little unrelated, but) is the difference between session-based authentication and token-based authentication that this ID that's shared is dynamic, or changing every time? Is this still the standard and modern way of doing it in 2020?
"Instead of express-session, I am using cookie-session as I am a beginner."
using cookie session does not make anyone beginner. If you are going to store large data, use express-session, cause it stores the data in the database or redis, keeps the database id of that data, so when it gets a request, fetch the database with that id and compare the request credentials. On the other hand, cookie-session stores the data upto 4kb in the cookie on the user browser and since only user-id is stored in the cookie with passport.js, generally cookie session is used.
passport.serializeUser(
(user, done ) => {
done(null, user.id); // stores the id<4kb
}
);
When client authorizes your app, google send the responds to your callback url.
app.get("/auth/google/callback", passport.authenticate("google"))
passport.authenticate() will call req.login() this is where passport.user gets generated. req.login() will initiate the serializeUser() which determines which data of the user should be stored in the session.
passport:{user:userId}
Now this object will be assigned to req.session. so we will have req.session.passport.user
Everytime when you make a request to a server, browser automatically checks if there is cookie set related to that server and if there is it automatically attaches the cookie to the request. If you were using token based authentication, you had to manually attach the cookie to request everytime you make a request. Cookie is just transportation medium, you store data and move the data, you can even store the token in cookie. Cookie is not just related to authentication. If you have server-side project, you have to set cookie.(this is just a side node).
"My understanding of cookie-session is that it sends a session ID every time, and this ID can be used to look up the database when needed."
so far I explained how session is created. Now what happens when user makes a request?. In app.js file you should have two middleares.
app.use(passport.initialize());
app.use(passport.session());
app.use(passport.initialize()) this function checks if req.session.passport.user exists, if it does it will call passport.session(). if it finds a serialized user object in the session, it will consider this req is authenticated. And then deserializeUser() will be invoked. it will retrieve the user and attach it to req.user
You don't need to use session. It is totally upto you. Just put {session: false} in route. You don't need to write passport.serializeUser and passport.deserializeUser.
cookie-session puts cookie on client system, and it is sent each time with request. passportjs search that cookie and run deserializeUser to convert it into object and attach it with request object.
express-session stores session data on the server; it only saves the session identifier in the cookie, not session data.
where as cookie-session is basically used for lightweight session applications. it allows you to store the session data in a cookie but within the client [browser]. Only use it when session data is relatively small and easily encoded as primitive values See this question for more understanding
const express = require('express');
const { Router } = express;
const router = new Router();
router
.get('/', passport.authenticate('google', { session: false }))

Authentication without Passport

I'm using active directory to authenticate users, so I thought I didn't need to use Passport and that all I would need to do is after the password checks out is to create a global(?) boolean with res.locals to indicate that the user has been authenticated.
I've tried something like this in a controller function:
ad.authenticate(username,password, function(err,auth) {
//some of the things I tried unsuccessfully -- should be true after logged in
res.locals.auth = auth
app.locals.auth = auth //app not defined
})
However, I've discovered that when I call a later function checking if the user is logged in as part of middleware for a diff route, res.locals.auth and app.locals.auth are either false or undefined. I've tried setting both vars in my server.js file at the beg with the code below but that didn't work either...
app.use((req, res, next) => {
app.locals.auth = false;
res.locals.auth = false;
next();
});
So my question is, what var/where should I be saving the authenticated status? Or should I just use passport instead because there's some security concern that I was unaware of? What is the point of the isMemberOf in passport setup example?
https://www.npmjs.com/package/passport-activedirectory
All I want to do is just check user credentials and basically recreate req.isAuthenticated in Passport because I couldn't figure out how to use it because of the isMemberOf.
Usually the server sends back a token containing some useful data (user or session id, expiration date) either by cookies or by JWT (json web token).
Then a client puts the token into every request to the server . The server validates expiration date and handles requests.
Cookies will be put into a request by the browser automatically. JWT should be put into a request by your client code.

Store session in client's browser using raw node.js and cookie without express

I am trying to store client session using raw node.js without express.
When a user logs in I have the username and password. Now, how to store a session in client browser using cookie. And how to identify the user when they refresh the tab or goes to another link.I don't want to use client-sessions module as I want to understand the approach.
any help will be appreciated.
First of all, I suggest you to watch everything about authentication in NodeJS It explains cookies in a part very well.
You have to give the browser some data to hold for it to use later, which being cookies. Browser uses this data to show the server what kind of authentications it has processed before for the server and the user to proceed without repetition.
In node.js, using client-sessions module, you can set a cookie by calling
app.post('/login', function(req,res){
User.findOne({password: req.body.userPassword}, function(err, user){
if(user){
req.session.user = user; //here you are setting the cookie for the client,
}
})
})
You could also specify what kind of cookie you want to set by just adding it a property
req.session.userEmail = user.email;
Now let's check how the server uses authentication
app.get('/someUrl', function(req,res){
if(req.session.user){
console.log("user exists!");
}
})
You can check what the client sends you by using session property of req object => req.session
To bind it with database you need to do,
if(req.session.user){
User.findOne({email: req.session.user.email}, func...)
}
So basically, with each request that client sends, this procedure is used by the server to identify the cookies and to make the web-app user-friendly with no repetition.
It is like giving every student an ID in a school for authentication.
Security
For security, the node module cookie-sessions encrypt data automatically when we add secret attribute in app.use() function. Please see using secret in client-sessions module

Allow connection only for authorised socket in sails.js

I am trying to implement some kind of security for socket.io clients in the sails.js backend (using version 0.12.x). To achieve this, I try to either prevent successful handshake for clients without a proper cookie (no authorised session beforehand) or like for HTTP request using passport.js to see if the client is authenticated.
In Sails.js documentation I've found that this should be possible, but I could not find any hint, how to do it really. On the other hand, looking for examples on the internet, people mostly don't use security for sockets, or use some old version of sails.js (<0.10).
The closest what I found until now, is for the config/sockets.js:
beforeConnect: function(handshake, cb) {
if (handshake.headers.cookie) {
console.log(handshake);
// TODO: check session authorization
} else {
return cb(null, false);
}
return cb(null, true);
},
This should check the cookie sent with the handshake, if it has a proper session. I have a hard time figuring out, how can I map the sid from the cookie to current sessions in sails.js, for deciding if the connection should be allowed.
Questions:
What is the best security practice for socket.io, if only a small number of clients is allowed (some 40-50 dynamic generated users should be allowed for connection), and nobody else?
How can I map the sails.sid from the cookie to active sessions?
What other configs could be a shortcut to my goal (e.g. setting some policies, that socket.io request use the same middleware as http)?
Thanks for any hint, link or suggestions.
What is the best security practice for socket.io, if only a small
number of clients is allowed (some 40-50 dynamic generated users
should be allowed for connection), and nobody else?
I don't know what is best. But there are two common approaches: token- and cookie based authentication.
Here is a nice visualization of both taken from https://auth0.com/blog/auth-with-socket-io/
I really like the token approach because there is no need for a session store. Hence the server application is decoupled from the client and also stateless.
How can I map the sails.sid from the cookie to active sessions?
Token approach: check out jsonwebtoken. When a user signs in you generate a token and send it to the client:
res.json({
user: user,
token: jwToken.issue({id : user.id })
});
Further you need a policy that checks if a token exists and validate it:
jwToken.verify(token, function (err, token) {
if (err) return res.json(401, {err: 'Invalid Token!'});
req.token = token;
next();
});
I found a complete tutorial that might help you: https://thesabbir.com/how-to-use-json-web-token-authentication-with-sails-js/
How to configure it with sails: you basically just send the token with each socket.io request and check the token inside a policy:
SailsJS - using sails.io.js with JWT

How to avoid sessions until logged in within Express

I cannot seem to figure a way to prevent Express/Connect to create sessions until I have a valid log in from the user.
The problem especially arises when using a DB-Backed Session Storage and calling the REST Services from non-browsers as in such cases, the Connect Session Object will create a new Session for each request which I do of course want to prevent.
However, I do need sessions whenever the user is authenticated as I am using Passport.js for authentication which requires sessions as well as I do require it to load session data from sent cookie information.
Looking at the source of the Connect Session Code, it seems it is always creating a new Session if none got sent from client without any option to prevent it..?
thanks
Alex
If you can easily identify calls to your API at query time you could do something like this:
app.use(function(req, res, next){
if ( req.path.indexOf("/api") == 0 ) return next();
else return express.session()( req, res, next );
});
This way the session middleware is only included if the request URL doesn't match some condition. I haven't tried this in anger though, so you might want to consider initialising express.session() outside the function, and make sure there aren't any other repercussions.

Resources