Authentication & Sessions in express.js/sails.js - node.js

Have been working through the sails cast tutorials and am confused about the way that sessions work.
In the tutorial, the user is marked as authenticated in the session controller by:
req.session.authenticated = true;
req.session.User = user;
res.redirect('/');
Why is the session being saved in the request?! My understanding is that the 'req' object in express.js is the information the browser sends to the server.
Shouldn't the server save this information elsewhere (won't the request object be deleted when theres another request?)
Furthermore, somehow the application retrieves the authentication status from another object session when templating a page with ejs:
<% if (session.authenticated) { %>
why isn't this variable set directly?
Probably a silly question but I am confused at how the logic works and online articles/tutorials aren't helping me understand...

It is common practice for express middleware (remember, Sails is built on express) to attach properties to the req object so it may be accessed in later middleware, and eventually your controllers. What happens behind the scenes is your req object comes in with a cookie containing the session ID, and then the session middleware uses that to retrieve the actual session data from some datastore (by default, and in-memory store is used. Super fast and easy for development, but not recommended for deployment), and then attaches that to the req object.
Regarding the value of session.authenticated in your EJS, by default Sails includes req.session in res.locals (accessible in views), so that value will be whatever is stored in the session via your controller.

The browser sends over the session id which is stored on a cookie. The session object is referenced by that session id which is stored server side. The session is attached to the request (for convenience I suppose). You can read more here https://github.com/expressjs/session#compatible-session-stores
I wouldn't know what is setting session.authenticated without seeing more code.

Related

Express session, how do I get the session after posting? I see the session ID in browser under cookies, but it's undefined in request object?

Sorry guys, I'm really new to sessions and cookies and I'm trying to understand the mechanism behind it. I wanted to add register/login to my simple website and in order to do I need to understand web authentication and I really think I will have tons of questions regarding this topic.
Initially, I have register page that sends info after clicking submit button to a node server using express.
I'm trying to see what happens, so I've created a session in post route, it's created in the browser (connect.sid), then I commented out the part that creates that session and just tries to redisplay the session object, but it's undefined, but I still can see the session in the browser's cookies section, so what's going on? Thanks
app.use(session({
secret:"my test secret",
cookie:{},
resave:false,
saveUninitialized:false
}))
app.post("/register", (req, res) => {
req.session.usertest = "testsession_hardcodedvaluefornow";
console.log(req.session.usertest); // -> this is okay when above line to create is uncommented
//but when I comment the session assignment, it becomes undefined?
res.send("In register...");
})
I can see the session cookie even after commenting out the create session and posting over and over.
connect.sid s%3A_TahsTv0xhY-iHIdjDRblYJ_aZZ5oiSd.do7JcOGR1FaXPcFFIQ6hg5AW%2B0XVsYwIRO8vndyjDzs
req.session.id produces a different value (not undefined) even if I delete my session in the browser, so not sure where that comes from.
There is no "usertest" key in the session object, therefore it is undefined. The reason it's not undefined when you uncomment that line is because you create that key yourself in that instant with that line.
You can get the whole session object by using req.session, the session id by using req.session.id and the session cookie by using req.session.cookie.
Edit
To further clarify: a session will be made for every connected client. That is why you can see the cookie in the browser. That has no meaning however, it's just a way to uniquely identify that client (without actually telling you who that client is). Any information about that session (whether they're logged in, user id,...) needs to be stored in a session store. Express-session will use memory store by default, if the server restarts all that information will be lost, which is why that key doesn't exist. In order to preserve that information it has to be stored in a persistent session store. More information on session store implementations for express-session and how to use them can be found here: https://www.npmjs.com/package/express-session
As for the cookie values you get, those are the default ones set by express-session since you haven't set any yourself. You can change the maxAge to let it expire (or set it so 10 years or more for a more persistent session), you can specify a domain to which that cookie belongs, you can set it to secure (to only allow it over secure connections, e.g. https) and httpOpnly is by default true. httpOnly cookies cannot be accessed/altered by the client (although you can see them in the browser), do not set this to false.

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

Are the variables stored in the Node.JS Express global namespace private to the current request?

Node.JS Express apps have a global object that acts as a "bag" you can attach data/objects to that is available to all the code in your application:
// Create an appRoot global variable that tells the code base what the root directory of this app is.
global.appRoot = path.resolve(__dirname);
My main concern is that I need to be sure that the global object is only global in the sense that all the code that operates in the context of the current client request an other has access the data in that object, and that the data is not available between or across requests. Otherwise I could be leaking data that must remain private to a particular request or user.
To make sure I'm being crystal clear, let's take an example scenario:
GET request #1: The name "john doe" is stored in global.userName
GET request #2: At the start of the request, global.UserName is unassigned and absolutely does not contain "john doe"
In other words, is the global object reinitialized with every single request or does it persist as long as the server is operational, available to all requests that reach the server and there aren't any "tricks" that could lead to unwanted data leakage across server requests?
The node.js global object is global to the entire node.js process. It doesn't have anything to do with Express. However, Express does have a few objects with different scopes that you can use for persisting data across a client request, or event across all client requests. From the Express docs:
res.locals
An object that contains response local variables scoped to the request, and therefore available only to the view(s) rendered during that request / response cycle (if any).
app.use(function(req, res, next){
res.locals.user = req.user;
res.locals.authenticated = ! req.user.anonymous;
next();
});
app.locals
The app.locals object has properties that are local variables within the application... Once set, the value of app.locals properties persist throughout the life of the application, in contrast with res.locals properties that are valid only for the lifetime of the request.
The Express app.locals object is similar to the node.js global object insofar as it being maintained in memory across multiple requests. However, it's local to an instance of Express, and should that instance be deleted, so will the app.locals object. The node.js global object differs in that it will stick around for the lifecycle of the entire node.js process.
Yes, global variables will persist for any request. Unless you spin another instance of your node application. If you're looking to some authentication/session tools there are quite a lot out there, like passport or cookie-parser

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!

How does passport js stores user object in session?

I am using node/express with passport in my development. I came across an article which says:
Express loads the session data and attaches it to the req. As passport stores the serialised user in the session, the serialised user object can be found at req.session.passport.user.
But to my surprise, the value for sessionID stores in the browser cookies remain the same before and after login. So where does the serialised user object is stored?
I thought that it was stored in the user sessionid cookie initially but it seems that this is not the case as I still can access my user object with req.session.passport.user
So where does the serialised user object is stored?
In Short
The serialized user object is stored in req.user by PassportJS taken from req.session.passport.user (which is is populated by Express) with the help of Passport's deserializeUser method.
Express adds the id of the session object into a cookie on user's browser, which is sent back to express in a header on every request. Express then takes the id from the header and search the session store (i.e. Mongo or whatever) and find the entry and load it to req.session.
PassportJS uses the content of req.session to keep track of the authenticated user with the help of serializeUser and deserializeUser methods (for more information on workflow of serializeUser and deserializeUser see my answer in this SO question).
Express is responsible for creating the session. when does the sessions gets created? That is when Express do not detect a session cookie. So the order in which you organize your session and passport configs in your app or server.js file is very important. If you declare your session and passport configs above static directory configs then all requests for static content will also get a session, which is not good.
See my answer to this SO question, where I have mentioned about static content access as well as how to selectively apply passport to certain routes, rather than default (you might not need to authenticate all the routes - hence you could avoid unnecessary session store lookup and de-serialization by attaching session only to requests that map to secure URLS see below).
//selectively applying passport to only secure urls
app.use(function(req, res, next){
if(req.url.match('/xxxx/secure'))
passport.session()(req, res, next)
else
next(); // do not invoke passport
});
There is one amazing tutorial that I highly recommend you to read up if you want to understand the workflow of PassportJS.
You can look at the sessionID in the cookie as a key to a database where the session data is stored. Depending on what session handler you use with express, and what storage policy you use the data will be stored in different ways. This means that the sessionID can be the same value both before login, after a successful login, and even after a user logs out.
If you use express-session with MemoryStore the data will be saved in the memory of the node process, indexed on the sessionID. Look here for initialization of the store and here for storing of the data.
You could create a store where the data is serialized to the cookie, but none such are listed in the compatible session stores.

Resources