How to persist additional data added on fly in Passport sessions - node.js

I have a simple authentication system built on Passport.js on top of Node.js. I have a use case where I need to persist Organisation ID in the session which is to be updated on hitting of a particular route.
I did this using the middleware:
app.use('/switchOrganization',function(req, res, next) {
if(req.user) req.session.passport.user.activeOrg = 'my org';
next();
});
But this doesn't persist the data in other routes:
app.route('/someRoute').post(function(req,res){
console.log(req.session.passport.user);
});
It doesn't contains the 'activeOrg' value. Where I am going wrong?

The user object is deserialized into req.user in the deserializeUser function. This happens on each request. So if you make change to req.user in one of the route handlers, and expect it to be persisted for the route handlers that follow it, it'll only be the case for that particular request. If /someRoute is requested anew, it will not have the the changes you made in another route which wasn't invoked in the new request.
You should instead persist the changes to database so that when the deserializeUser function is called for the next request, it'll have your data from the beginning.

I am using redis sessionStore. And if I write to req.session, then data persists on redis store:
req.session.access_token = result.access_token;
req.session.refresh_token = result.refresh_token;
req.session.instance_url = result.instance_url;
Redis Screenshot

Related

express-session middleware to check authentication

I have a question about the usage of sessions with express-session. I really don't understand how the sessions are secure. For example in the following official guide: https://expressjs.com/en/resources/middleware/session.html they create a middleware to check if the user is authenticated:
// middleware to test if authenticated
function isAuthenticated (req, res, next) {
if (req.session.user) next()
else next('route')
}
But I don't understand, why isn't this middleware checking that the session is in fact, inside the DB? An attacker could just modify the session cookie with random values and there would be still some value in the user field, even if it's a garbage value, no? So the function still would think this is an authenticated user.
Why is this not possible?
In my case, I am setting the userId in the session and then every time someone makes a request, I retrieve its userId, but I do not understand, what if someone modifies the cookie and gets a random userId value? My application will think this user is authenticated, correct?
why isn't this middleware checking that the session is in fact, inside the DB?
This check, which you rightly expect to be done, is already done before, in the express-session middleware: This looks up the value of the session cookie in the session storage (which can be a database) and populates req.session accordingly. Since the value of the session cookie is unguessable, an attacker who puts in a random value, will make req.session undefined, and the isAuthentication check will fail, as it should.

Express req.session is set and then empty when trying to POST

I have a MERN stack blog app that I'm making as a learning exercise. I'm relatively comfortable on the front end but have limited experience in node. I'm adding authentification after following a couple tutorials to get this far. I'm using passport.js as a framework to make a request to Google, get back an id and save as session info. However, after logging in, req.session is empty when making a post request, even though I can see a cookie in the dev tools.
I'm using bcrypt's hash to obscure the actual id, but that may not be best practice.
in blogAuth.js: req.session is defined.
bcrypt.hash(req.user._id.toString(), saltRounds, function(err, hash) {
req.session.user = hash;
//session is set here.
console.log(req.session); res.redirect(http://localhost:8080/articles/loggedIn);
});
but in api/articles.js: req.session is empty
router.post("/", (req, res, next) => {
const { body } = req;
// session is empty here. Why?
console.log(Session user, ${req.session.user});
console.log(req.session);
I have tried:
Including proxy in the client package.json:
express req.session empty with cookie-session
using withCredentials set to true when sending the POST from the
client:Node + Express + Passport: req.user Undefined
Rearranging the order of middleware: Routes must always come
afterward, but I feel like I'm doing this blindly and it usually results in an error
Here's some of the relevant files:
Server side:
- app.js
- blogAuth.js
- passport.js
- api/articles.js
Client side:
- the POST req
Entire project
I believe this is an issue with ordering. What is a good way to ensure that I order my middleware correctly? Or if the order looks correct, where else could this issue becoming from?
You are trying to use cookie-session as well as express-session. Since both of them will try to control the fate of req.session object, you will end up with empty session always.
Just remove one of them, and your session will be persisted.

Sharing a variable between 2 routes express

I wanted to know if there is a way to share variables between 2 routes in expressJS without declaring it as a global. Consider I have the following routes:
exports.routeOne = (req,res) => {
var myVariable='this is the variable to be shared';
}
exports.routeTwo = (req,res) => {
//need to access myVariable here
}
How can this be done ?
===============
Note
This answer is answering the wrong question, but it might still be useful for others who also misinterpreted the question like I did, so I'm keeping it here for now.
===============
In order for the variable to exist it would have to first execute routeOne and then execute routeTwo. This is a pretty common scenario with express. To get the details on how this works read up on middleware (http://expressjs.com/en/guide/writing-middleware.html) and understand that each route is middleware.
The common pattern solution here is to add a new property to either the req or res object that stores your variable. Then you tell the route to call the next middleware. The next middleware has access to the same req and res so it also has access to the property and value that you just stored.
There is nothing wrong with this practice as most middleware does it. For example the body-parser middleware (https://www.npmjs.com/package/body-parser).
Here is an example of how your code might run:
routes.js
exports.routeOne = (req,res,next) => {
req.myVariable='this is the variable to be shared'
next()
}
exports.routeTwo = (req,res) => {
//need to access myVariable here
console.log(req.myVariable)
}
index.js
const express = require('express')
const routes = require('./routes.js)
const app = express()
app.use(routes.routeOne)
app.use(routes.routeTwo)
app.listen(3000)
One of the awesome things about NodeJS is that you can store state in variables. The process that runs your NodeJS server continues to run without restarting for each request that comes in. So any variables you store using GLOBAL.myVarName or variables that you store within the scope of a module (a single JavaScript file) will persist... until the process quits. The process could quit if the server goes down or if an Error or other exception is throw that is not caught. You can set up a process manager to keep it running, but your in memory variables are now lost.
I would recommend using variables that are scoped at a higher level for caching, but if the data is important it should be stored to and read from a database as needed.
Here is an example of your routes.js module. Any variable you declare outside of functions are scoped to this file. In other words, the variables are global to this file. You can read up more on that at https://nodejs.org/dist/latest-v8.x/docs/api/modules.html and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.
routes.js
let variableScopedToModule = 0
exports.routeOne = (req, res) {
variableScopedToModule++
}
exports.routeTwo = (req, res) {
console.log(variableScopedToModule)
}
If it is important that you never loose the variables state, and assuming you are not running the server on multiple processes for load balancing, then you could do something like this:
routes.js
const db = require('./my-db-controller')
let cachedValue
exports.routeOne = async (req, res) {
if (cachedValue === undefined) cachedValue = await db.getValue()
cachedValue++
db.setValue(cachedValue)
}
exports.routeTwo = (req, res) {
console.log(cachedValue)
}
This second solution is more complex because you'll need to understand promises as well as async and await. Also this solution will not work if you are using a load balencer unless you use something like Redis. Alternatively you can just read and write to the database for each request instead of using in memory caching.
For user-specific data that you want to persist from one request to the next, you can't just store data in simple server-side variables because server-side variables are freely shared among all users who make requests of your server.
The usual way to store server-side data that is user-specific is to use a session object. In a nutshell, when a user makes a request, some session middleware (which runs on every request) checks to see if a session cookie exists. If it does not, then one is created. The session cookie servers to uniquely identify that particular user when they make future requests.
Once you have a unique session cookie, the session middleware can create a session object that corresponds with that session cookie. Typically, there is a unique ID in the session cookie that servers as a lookup key for the session object.
Now, whenever that user makes a request of your server, the session middleware will look at the session cookie, get the encrypted session id out of it, decrypt the id, look up the session object that corresponds to that id and then make that session object available to your request handlers, usually in req.session. Your request handlers then have full access to the session object and can add, remove or modify your own properties on that session object.
express-session is common piece of middleware that is used for implementing sessions with nodejs/express. There are plenty of examples for how to use it in the documentation so I won't repeat that all here. Here's one such example in the doc.
By default, express-session uses a memory store (which just means the session objects are kept in memory). This can be fine for simple uses, but it has some limitations and express-session does not recommend it for production use. One major limitation of keeping the sessions in memory is that if the server crashes or restarts, all session data is lost. There are dozens of add-in object stores for express-session, most of which store data more durably such as in a database on disk.

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.

Node, express, passport - updating session after updating record

I'm rather new to node, I have started writing a small app and am working on my user auth and profile. I'm using express, passport and ejs. I've got passport working and have my user redirecting to a profile page that requires additional data before the user begin's to use the application. My question is:
What's the proper way to update the user's session (created at passport.authentication) when a user updates their profile data? I would like to update the user session in order to hit it rather than the data base for basic user data.
If your using express you have middleware that looks like:
function (res, req, next){}
When you get session data you can add it to the req object.
function (res, req, next){
// get the session here...
req.session = session;
}
Then any other middleware will have access to the req.session object which will contain the user's session.

Resources