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

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

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 }))

How to read PassportJS session cookie with ngx-cookie?

I'm learning Angular with a MEAN stack project. Full code is here: Angular front-end, Node.js API.
On the back-end, I use Passport authentication with the default session-based behaviour, and I have local, Google and Facebook strategies set up. Passport will insert user data in the session cookie, to be parsed and used by the front-end to display user name, email address, profile pic, etc.
So now in the back-end, what I need to do is retrieve the cookie and deserialize it, then write methods to use said cookie to get user data, as well as a basic isLoggedIn(), that would just check if a valid cookie is present.
To do that, I've tried both ngx-cookie and ngx-cookie-service and have the same problem with both: I can create and read a cookie that I've created, but the 'session' and 'session.sig' cookies created by Passport remain invisible to the getAll method (and any get('session')).
All code handling that is inside authentication.service.ts. Currently all methods are meant for a token-based auth, so I need to change them. Specifically, this is the method I use to test cookie handling:
public getCookies() {
this.cookies.set('test', 'yay');
console.log('test: ', this.cookies.check('test'));
const allCookies = this.cookies.getAll();
console.log('allCookies: ', allCookies);
return allCookies;
}
The console output of that code shows only one cookie, 'test'. On the browser dev tools, I see there are two more cookies, 'session' and 'session.sig', that I want access to. But how?
Thanks!

Cookies handling when client-side is also an ExpressJS app

As far as I'm concerned, for a server side application to know what clients are communicating with it, it will save a cookie in the client with the session ID.
That is indeed what express-session a popular package for session storage in ExpressJS says in the documentation
Note Session data is not saved in the cookie itself, just the session ID. Session data is stored server-side.
So I believe I can assume this is strategy used by Express to maintain user data in sessions as well.
I did something else: I'm using Redis to store the Session data in my ExpressJS server app.
So having said that, my problem is that my client application is also an Express app. I have a nodejs app with Express both for client and server. There is a SPA involved in this problem, but it communicates with the 'express client' so it appears to be a different problem.
So everytime I send a request from Express Client to Express Server, there is not cookie being passed, so it can't identify a session ID and creates a new one, generating lots of garbage in Redis and making the session solution useless.
How should I save or fake a cookie in the Express Client app, or, even better, how this kind of problem is solved?
Actually if I knew what the Express Server is expecting in the request (a cookie, a header or whatever) I think I can solve the problem.
Anyone know what to do?
#Solved
Alright, so, in my nodejs client application I did the following:
login(req,res,next){
var options = {
url : 'http://localhost:8090/user/login_handler';
};
request(options, function(error,response,body) {
var cookie_string = response['headers']['set-cookie'][0].split(';')[0];
req.session.cookie_string = cookie_string;
});
}
check(req,res,next){
var options = {
url : 'http://localhost:8090/user/check_handler',
headers: {
'cookie':req.session.cookie_string
}
};
request(options, function(error,response,body){
res.json( body);
});
}
In short, when the session is created in the server side, it will respond with headers to tell the client to create a cookie. I save the important information to pass as a cookie in a different moment. The server-side then read the headers in the middleware and load the correect data to the session.
Without knowing the details of your architecture I would guess that what you want is to either set the saveUnitialized option to false, and not save the extraneous sessions, or only apply the express-session middleware to certain routes in your "Express Server" application

Express JS routing based authentication

I have created node js app using express framework.
I have created middleware for restricting access to some routes.
Middleware actually works fine. but i have difficulties in displaying data.
Suppose In My app i have created route for display list of countries('/country/master')i.e html page which is using internally different/default route ('/country/') to get data from mongoDB.
In this case user will not able to see data cause i have not given permission to "/" routes. but i want to display data but not allow him to make use of "/" route to check data.
How can i deal with this case ????
The answer depends on your authentication strategy i.e. are you using session identifiers, access tokens, etc.
In either case I suggest that you break out the credential exchange (aka login) from the authentication. They should be separate middleware functions. Below is an example of what this looks like.
While this answers your question, specific to ExpressJS, it does leave out a lot of other details that matter when you are building an authentication system (like how to securely store passwords). I work at Stormpath, we provide user management as an API so that you don't have to worry about all the security details! It's very easy to integrate our API into your application, using the express-stormpath module. You'll have a fully featured user database in minutes, without having to setup mongo or a user table.
All that said, here's the example:
/* pseudo example of building your own authentication middleware */
function usernamePasswordExchange(req,res,next){
var username = req.body.username;
var password = req.body.password;
callToAuthService(username,password,function(err,user){
if(err){
next(err); // bad password, user doesn’t exist, etc
}else{
/*
this part depends on your application. do you use
sessions or access tokens? you need to send the user
something that they can use for authentication on
subsequent requests
*/
res.end(/* send something */);
}
});
}
function authenticate(req,res,next){
/*
read the cookie, access token, etc.
verify that it is legit and then find
the user that it’s associated with
*/
validateRequestAndGetUser(req,function(err,user){
if(err){
next(err); // session expired, tampered, revoked
}else{
req.user = user;
next();
}
});
}
app.post('/login',usernamePasswordExchange);
app.get('/protected-resource',authenticate,function(req,res,next){
/*
If we are here we know the user is authenticated and we
can know who the user is by referencing req.user
*/
});
You can positioning of middleware in you app.for example:-
app.get('/country/master',function(req,res){
})
app.use(function(req,res){
your middle ware for providing authentication
})
// other routes where authentication should be enabled
app.get('other urls')

Create session only after successful authentication in express

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

Resources