Cannot get value of req.user for Passport.js - mongodb

I spent hours figuring things out why I cannot get the value of req.user when Passport.js serialized a user. But magically, when I deleted the database collection that holds the session, it worked again.
My stack:
Vue.js
Express
Mongoose MongoDb (I store my data on Atlas)
Node.js
I use express-session and connect-mongo to create and save session data and use it to serialize and deserialize user using Passport.js
App.js:
const session = require("express-session");
const passport = require("passport");
const MongoStore = require("connect-mongo")(session);
// Sessions
app.use(
session({
secret: "this is a sample secret",
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
})
);
//Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
Then I call req.user on a route like this:
router.get("/users", async (req, res) => {
try {
if (req.user) {
res.send(req.user)
} else {
res.send("no-user-found",)
}
} catch (err) {
console.error(err);
}
});
I'm calling /api/users on the front-end with Vue.js and Axios hosted on localhost port 8080. Also, tested on the server itself by calling http://localhost:3000/api/users
Now it works, now that I have deleted the sessions database collection on MongoDb Atlas.
I'm just wondering why this happens? Will it repeat again in the future?

Related

Next.js middleware to connect mongoose

I am working on a Next.js project and I want to connect it with MongoDB using mongoose. I want to make a middleware to run the connect function inside so I don't have to call connect function in each file I am using a mongoose model in.
this is my connect file:
// src/utils/connect.js
import mongoose from 'mongoose'
// getting the connection uri
const MONGO_URI = process.env.MONGO_URI
// checking if MONGO_URI is defined
if (!MONGO_URI) {
throw new Error(
'Please define the MONGO_URI environment variable inside .env.local'
)
}
// maintaining a cached connection to prevent reconnection (connections growing exponentially during API Route usage)
let cached = global.mongoose
// restiing the connection if there was no cached connection
if (!cached) {
cached = global.mongoose = null
}
/**
* mongodb connection
*/
export default async function connect() {
// returning the cached connection if it exists
if (cached) {
return cached
}
cached = await mongoose.connect(MONGO_URI, {
bufferCommands: false,
useNewUrlParser: true,
useUnifiedTopology: true
})
return cached
}
it will connect mongoose with my MongoDB database and caches the connection for future use.
this is one of my example API routes:
// src/pages/api/test.js
import connect from '../../utils/connect'
import Test from '../../models/Test';
export default async function handler(req, res) {
// connect
await connect()
const data = await Test.find({});
res.status(200).json({ name: 'John Doe', data })
}
now what I want to do is to get rid of that await connect() function in all routes and instead make a middleware to run the connect. and also is it better do so or not?

Passport OAuth2 strategy / facebook strategy is loosing user

I am trying to authorize a pre logged in user with a Facebook account. I want to store the auth token of Facebook to later post stuff using my CMS.
I am using Express/NodeJS and Passport JS.
My FacebookStrategy looks like this:
module.exports = new FacebookStrategy(
{
clientID,
clientSecret,
callbackURL: `${config.apiUrl}/v1/auth/connect/facebook/callback`,
passReqToCallback: true
},
async function(req, token, tokenSecret, profile, done) {
console.log("SESSION?", req.session)
console.log("THIS SHOULD BE SET!", req.user) // But is not!
// Stuff is done.
done(null, token, {savedConnectionForLaterUse});
}
I also have two routes:
router.get('/connect/facebook',
API_KEY_OR_JWT_AUTH_MIDDLEWARE,
(req, res, next) => {
// Save authInfo in session
Object.assign(req.session, {account: req.authInfo.account._id, user: req.user._id})
passport.authorize('facebookConnect', {
failureRedirect: `${frontUrl}/settings/connections`,
scope: facebookOAuthScopes, // This is an array of scopes I need
})(req, res, next)
},
);
router.get('/connect/facebook/callback',
passport.authorize('facebookConnect', {
failureRedirect: `${apiUrl}/v1/auth/connect/facebook/failure`,
}),
(req, res) => {
const { session: {connection} } = req;
res.redirect(`${frontUrl}/settings/connections/edit/${connection}`);
}
);
When I am running this on my local machine it works due to the fact that the session is there and in the session I can find my user for later use. As soon as I am deploying this on a server (with kubernetes) the session is gone.
The configuration of the express session looks like this:
app.use(
expressSession({
secret: config.security.secret,
resave: true,
saveUninitialized: true,
cookie: {
sameSite: 'none', // This was something I tried.. didn't help thou
secure: true,
},
})
)
Can anyone point me into the right direction? What am I doing wrong?
Thank you all for your help in advance. I am really at the end of my knowledge. The struggle is real! :D

Express session, passport and connect-pg-simple issue in production

This is my first time posting a question up here. I hope you guys can help me out with this. I am fairly new to node.js, express, so sorry in advance for my inexperience.
I am currently having a problem with my authentication session in my node.js, express app. I use Passport.js to handle my authentication, I store the login session with connect-pg-simple (a PostgreSQL session store). After clicking the login button, the session was stored inside my PostgreSQL database, but somehow express couldn't find it. In fact, it stores the session twice in the database, but only one of them got the passport cookie in it.
This issue was not present when the server was still on localhost. It appears when I host my server on Heroku.
Also, whenever I push to heroku repo, it shows this warning:
"connect.session() MemoryStore is not designed for a production environment, as it will leak memory, and will not scale past a single process."
My guess is I didn't connect express session to the PostgreSQL express store properly. Below is my code:
This is how I set up the PostgreSQL database:
const Pool = require("pg").Pool;
const pool = new Pool({
user: process.env.PGUSER,
password: process.env.PGPASSWORD,
host: process.env.PGHOST,
port: process.env.PGPORT,
database: process.env.PGDATABASE
});
module.exports = pool
This is how I set up the session:
const poolSession = new (require('connect-pg-simple')(session))({
pool : pool
})
app.set('trust proxy', 1);
app.use(session({
store: poolSession,
secret: process.env.SESSION_SECRET,
saveUninitialized: true,
resave: false,
cookie: {
secure: true,
maxAge: 30 * 24 * 60 * 60 * 1000
} // 30 days
}));
app.use(passport.initialize());
app.use(passport.session());
This is the image of 2 sessions were store in the database when clicking the login button
https://i.stack.imgur.com/lzAby.png
This is my login route (when click the login button):
router
.route("/signin")
.post((req, res, next) => {
console.log("Signing in...")
passport.authenticate('local', function(err, user, info) {
//code....
req.logIn(user, function(err) {[enter image description here][1]
console.log(user);
if (err) {
console.log(err);
res.send(apiResponse(500, err.message, false, null))
return next(err);
}
console.log(req.sessionID); //The id of the 1st session store in db
console.log(req.isAuthenticated()) //True
res.redirect('/auth');
});
})(req, res, next);
})
This is the route that is redirected to when login successfully:
router.get("/", (req, res) => {
console.log("/ ", req.isAuthenticated()); //False
console.log("/ ", req.sessionID); //The Id of the 2nd session store in db
if(req.isAuthenticated()){
//Notify user login success
}
});
I have been stuck here for a few days now. Please tell me if you need more code!

Logout in ExpressJS, PassportJS and MongoStore

Im using PassportJS for authentication and MongoDB for session
In app.js:
app.use(express.session({
store: new MongoStore({
db: mongoose.connection.db
})
}));
For logout:
app.get('/logout', function(req, res){
req.session.destroy(function (err) {
res.redirect('/');
});
});
In logout, do I need to remove session document in mongo?
PassportJS added a logout() function to req.

Node.js connect-mongo database connection problem

This is a very weird problem with "connect-mongo"
In my server, I have two scripts.
1) create the express server with session with Mongo DataStore: It has no problem for connection or creating the session.
MongoStore = require('connect-mongo'),
app = require('express').createServer(
express.session({ secret: cfg.wiki_session_secret,
store:new MongoStore({
db: 'mydatabase',
host: '10.10.10.10',
port: 27017
})
})
);
2) just create the store without express:
var MongoStore = require('connect-mongo');
var options = {db: 'mydatabase'};
var store = new MongoStore(options, function() {
var db = new mongo.Db(options.db, new mongo.Server('10.10.10.10', 27017, {}));
db.open(function(err) {
db.collection('sessions', function(err, collection) {
callback(store, db, collection);
});
});
});
That will throw the connection problem:
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Error connecting to database
at /home/eauser/node_modules/connect-mongo/lib/connect-mongo.js:106:13
at /home/eauser/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/db.js:79:30
at [object Object].<anonymous> (/home/eauser/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/connections/server.js:113:12)
at [object Object].emit (events.js:64:17)
at Array.<anonymous> (/home/eauser/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/connection.js:166:14)
at EventEmitter._tickCallback (node.js:126:26)
I just don't know why..
connect-mongo is a middleware for the connect framework, which express is based on.
So, you must use the middleware with the express framework or the connect framework, otherwise it won't work. It's not written to be a standalone session library.
You can go for mongoose to connect. Install using npm command
npm install mongoose
Install mongoose globally
npm install -g mongoose
app.js
var mongoose = require("mongoose");
This module has callback in the constructor which is called when the database is connected, and the collection is initialized so it won't work as you expect.
I've the same problem than you and I wanted the same interface that you aim here. So I wrote another module called YAMS - Yet Another Mongo Store. This is an example with YAMS:
var MongoClient = require("mongodb").MongoClient;
var Yams = require('yams');
var store = new Yams(function (done) {
//this will be called once, you must return the collection sessions.
MongoClient.connect('mongo://localhost/myapp', function (err, db) {
if (err) return done(err);
var sessionsCollection = db.collection('sessions')
//use TTL in mongodb, the document will be automatically expired when the session ends.
sessionsCollection.ensureIndex({expires:1}, {expireAfterSeconds: 0}, function(){});
done(null, sessionsCollection);
});
});
app.usage(express.session({
secret: 'black whisky boycott tango 2013',
store: store
}));
This is in my opinion more flexible than the connect-mongo middleware.