PassportJs session not working when wrapping athenticate function - node.js

so i have this problem with passportJS local strategy
it can't persist logins when i wrap passport.athenticate inside a function
when i try to login on the route /loginT then go to /whoami it works just fine
but when i use /login it responds with user object , but when i hit /whoami it log undefined
i think i made a mistake somewhere but i can't find what's wrong with it
thank you
here's passport config
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy
const UserDB = require('../models/users')
const { UserStatus } = require('../middleWares')
const signIn = new LocalStrategy (
function( username , password , callback) {
UserDB.findOne(
{$or : [{username:username},{email:username}]},
async function(err,user){
if (err) callback({
success:false,
code:403,
message:err,
}, false) ;
if (!user)
callback({
success:false,
code:403,
message:'Username not found',
}, false)
if (!(await user.verifyPassword(password)))
callback ({
success:false,
code:403,
message:'Username or Password is incorrect',
},false)
if(user.status === UserStatus.PENDING_EMAIL_ACTIVATION) {
callback({
success:false,
code:93,
message:'Please Activate your account first',
},false,)
}
callback(null,user)
}
)
}
)
passport.use('local-signin',signIn)
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
UserDB.findById(id, function (err, user) {
done(err, user);
});
});
module.exports = passport;
userRoute file
router.post('/loginT',passport.authenticate('local-signin',{
failureRedirect:'/Login',
successRedirect:'/'
}))
router.get('/whoami',async (r,res) => {
console.log(r.user)
return res.send({user:r.user})
})
router.post('/login',async (r,s)=>{
passport.authenticate('local-signin',{},function(err,_user,info){
if(err) s.send(err)
if(_user) s.send({
success:true,
code:200,
data:{..._user._doc,
password:null,
_id:null
}})
})(r,s)
})
server.js
const passport = require('./passport');
app.use(require('express').json())
app.use(cookieParser());
app.use(require('express-session')({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());

*** SOLVED ***
i forgot to use request.logIn(user, function)
so i had to make the login route as next
router.post('/login',async function (r,s){
passport.authenticate('local-signin',{},function(err,_user,info){
if(err) s.send(err)
r.logIn(_user,function(error) {
if(error) return s.send({
success:false,
code:403,
message:error,
})
return s.send({
success:true,
code:200,
data:{..._user._doc,
password:null,
_id:null
}})
})
})(r,s)
})

Related

Passport JS req.user is undefined

I've seen this question posted else where, however, none of those solutions appeared to work for me. Upon trying to console log the req.session and req.user, I have a return of the session as shown below, however, the req.user returns as undefined. I believe there is an issue when serializing the user as VS code alerts me that the "'id' property does not exist on type user" in the passport.serialUser function, but it console logs user.id properly (the object id of my user document).
If anyone is aware of what might be cause of the user.id property not existing/the user being undefined I would appreciate it.
passport.js file:
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
const User = require("../models/User");
const verifyCallback = (username, password, done) => {
User.findOne({ username: username })
.then((user) => {
if (!user) {
return done(null, false);
}
// Validate Password
bcrypt.compare(password, user.password).then((isMatch) => {
if (isMatch) {
return done(null, user);
} else {
return done(null, false);
}
});
})
.catch((err) => {
done(err);
});
};
const strategy = new LocalStrategy(verifyCallback);
passport.use(strategy);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((userId, done) => {
User.findById(userId)
.then((user) => {
done(null, user);
})
.catch((err) => done(err));
});
index.js file:
session({
secret: process.env.SECRET,
resave: false,
saveUninitialized: true,
store: sessionStore,
cookie: {
maxAge: 1000 * 60 * 60 * 24,
},
})
);
// Passport Auth Middleware
const passportConfig = require("./config/passport");
// Initialize Passport and Use Session for Serialize/Deserialization
app.use(passport.initialize());
app.use(passport.session());
app.use((req, res, next) => {
console.log(req.session);
console.log(req.user);
next();
});
console log:
cookie: {
path: '/',
_expires: 2021-11-17T02:08:23.650Z,
originalMaxAge: 86400000,
httpOnly: true
}
}
undefined
User document example:
{"_id":{"$oid":"6186c13beb18d33d5088f7b2"},
"username":"coolguy9",
"password":"$2b$13$4p5apH8Q8k8hP4WpCNt6/O40M9I0jlkG.LXIE3d/V89Kmtmk1plxa",
"firstname":"Bob",
"lastname":"Woodhull",
"team":"Warehouse",
"createdAt":{"$date":{"$numberLong":"1636221243904"}},
"updatedAt":{"$date":{"$numberLong":"1636221243904"}},
"__v":{"$numberInt":"0"}}```
Solved the issue. In my loginAPI.js file on my front end, which contains the axios instance, I needed to include the option withCredentials: true.
Example:
baseURL: "http://localhost:8000/api/",
timeout: 1000,
withCredentials: true,
});

passport.deserializeUser() not being called and req.user is undefined

Alright, I've been racking my brain over this for hours now. When I call my 'sign-in' route the passport middleware works fine and returns with a req.user obj, but when I call another route after that, req.user for that other route is undefined. Where exactly have I messed up here? I'm not sure it matters, but I am calling my API routes from a react client.
auth
router.post(
"/sign-in",
passport.authenticate("local"),
async (req, res, next) => {
if (!req.user) console.log("NO USER!*******************");
try {
const user = _.get(req, "user", "");
res.status(200).json(user);
} catch (e) {
console.log({ e });
return res.status(400).json(false);
}
}
);
My Server
app.use(cors());
app.use(cookieparser());
app.use(logger("dev"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(
session({
secret: "super",
resave: false,
saveUninitialized: true,
cookie: { secure: false, maxAge: 4 * 60 * 60 * 1000 }
})
);
require("./utils/passport");
app.use(passport.initialize());
app.use(passport.session());
./utils/passport
const _ = require("lodash");
const LocalStrategy = require("passport-local").Strategy;
const { PrismaClient } = require("#prisma/client");
const prisma = new PrismaClient();
const bcrypt = require("bcrypt");
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(async function(id, done) {
console.log("");
console.log("deserializeUser*************************");
console.log("");
try {
const user = await prisma.user.findOne({ where: { id } });
if (!user) {
return done(null, false);
}
return done(null, user);
} catch (e) {
done(e);
}
});
passport.use(
new LocalStrategy(
{
passReqToCallback: true,
usernameField: "email"
},
async (req, email, password, done) => {
try {
const user = await prisma.user.findOne({ where: { email } });
if (!user) {
return done(null, false);
}
await bcrypt.compare(
password,
_.get(user, "password", ""),
(err, result) => {
if (!result) {
done(null, false);
}
done(null, user);
}
);
} catch (e) {
done(e);
}
}
)
);
I suspect something is wrong with the portion where you have your post method with passport authenticate.
This portion may be deleted:
if (!req.user) console.log("NO USER!*******************");
I think the asynchronous may produce here odd results. Then for the sake of troubleshooting, include in your
const user = _.get(req, "user", "");
real data, such as real user data. Thus you will be able to verify that the data is passing through.

Not able to solve passport-saml req.isAuthenticated() false issue

I'm new to saml and using Nodejs + Express + passport-saml + okta identity provider. I know this is a duplicate question but somehow I am not able to solve this by looking lot of threads on the internet.
I used yeoman express generator for project. Here are my settings:
Server is behind ngnix using https. So, if I hit https://mywebsite.com, it redirects internally to localhost:3000 on that server.
express.js
var samlUtil = require('./saml-util.js');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
limit: '2mb',
extended: true
}));
app.use(compress());
app.use(cookieParser(config.SERVER_KEYS.SERVER_SECRET));
app.use(express.static(config.root + '/public'));
app.use(methodOverride());
app.use(session({
secret: config.SERVER_KEYS.SERVER_SECRET,
resave: false,
saveUninitialized: true,
cookie: {
expires: false,
secure: true
}
}));
app.use(samlUtil.initialize());
app.use(samlUtil.session());
app.get('/saml/response', samlUtil.protected, function(req, res) {
res.end("Hello " + req.session.passport.user);
});
app.get('/saml/invalid', function(req, res) {
res.end("Authentication failed");
});
app.post('/saml/callback', samlUtil.authenticate('saml', {
failureRedirect: '/saml/response/',
failureFlash: true
}), function(req, res) {
req.session.save(function() {
res.redirect('/saml/response/');
})
});
app.get('/saml/login', samlUtil.authenticate('saml', {
failureRedirect: '/saml/response/',
failureFlash: true
}), function(req, res) {
res.redirect('/saml/response/');
});
saml-util.js
var path = require('path');
var passport = require('passport');
var root = path.normalize(__dirname + '/../..');
var constant = require(root + '/app/util/constants.js');
var config = require(constant.APP_CONFIG_FILE);
var SamlStrategy = require('passport-saml').Strategy;
var users = [];
function findByEmail(email, fn) {
for (var i = 0, len = users.length; i < len; i++) {
var user = users[i];
if (user.email === email) {
return fn(null, user);
}
}
return fn(null, null);
}
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing.
passport.serializeUser(function(user, done) {
console.log('serializing');
done(null, user.email);
});
passport.deserializeUser(function(id, done) {
console.log('de-serializing');
findByEmail(id, function(err, user) {
done(err, user);
});
});
passport.use(new SamlStrategy({
issuer: config.SAML.ISSUER_URL,
path: config.SAML.PATH,
entryPoint: config.SAML.ENTRY_POINT,
cert: config.SAML.CERTIFICATE,
}, function(profile, done) {
console.log('got profile');
console.log(profile);
if (!profile.email) {
return done(new Error("No email found"), null);
}
process.nextTick(function() {
console.log('Finding by email');
findByEmail(profile.email, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
console.log('new user');
users.push(profile);
return done(null, profile);
}
console.log('existing user');
return done(null, user);
})
});
}));
passport.protected = function protected(req, res, next) {
console.log('is isAuthenticated =' + req.isAuthenticated());
if (req.isAuthenticated()) {
return next();
}
res.redirect('/saml/invalid');
};
exports = module.exports = passport;
What is happening:
I can hit the URL: /saml/login
Gets redirected to the okta login page (where I have identity settings)
I login successfully
I'm redirected to the URL: /saml/callback with response:
{issuer:
{ _: 'http://www.okta.com/exkctyzcknbMikNjl0h7',
'$':
{ Format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity',
'xmlns:saml2': 'urn:oasis:names:tc:SAML:2.0:assertion' } },
sessionIndex: '_3acb290873febaf825cd',
nameID: 'ashutosh#myemail.com',
nameIDFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
nameQualifier: undefined,
spNameQualifier: undefined,
firstName: 'Ashutosh',
lastName: 'Pandey',
email: 'ashutosh#myemail.com',
getAssertionXml: [Function] }
In the /saml/callback URL, I can see value returned in req.user but
req.isAuthenticated() in saml-util is always returning false.

passportjs deserializeUser nothing happen after call

am using nodejs and express with passportJS to auth my users with session (very important to use session in my case)
basically, i have a dashboard and I want to auth each request using isLoggedIn middleware
after the user logged in, the function (deserializeUser) get running and run the findById but nothing happened after that !!!
below my code
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// required for passport
app.use(session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
console.log("serializeUser =>"+user);
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log("Deaire ==>"+id);
models.User.findById(id, function(err, user) {
if(user)
return done(false,user);
return done(false,false);
});
});
passport.use(new UniqueTokenStrategy({
session: true},
function (token, done) {
models.User.findOne({where: {token: token}}).then(function (user) {
models.userHasRoles.findOne({
where: {
userId: user.id
}
}).then(function (hasRoles) {
if (!hasRoles) {
return done(null, false);
}
return done(null, user);
});
})
}
));
passport.use('local',new LocalStrategy({
usernameField: 'phone_number',
passwordField: 'pin',
session: true,
passReqToCallback : true
},
function(req,phone_number, pin, done) {
console.log("Inside local str");
models.PhoneVerification.findOne({ where: {phoneNumber: phone_number, pinCode:pin}}).then(function (phoneVerification) {
if(phoneVerification==null){
models.configuration.findOne({
where:{name :"default pin"}
}).then(function (configuration) {
if(configuration.detail==pin){
}else {
return done(null, false, {message: "Couldn't login"});
}
})
}
models.User.findOne({where: {phoneNumber: phone_number}}).then(function (user) {
if(user == null){
models.User.create({
phoneNumber: phone_number,
token: randtoken.generate(32)
}).then(function (user) {
return done(null, user);
});
}else {
user.update({token: randtoken.generate(32)}).then(function () {
return done(null, user);
});
}
});
})
}
));
so till now everthing is good , i can check if am not logged in , but if i am really logged in then the code get idle there
here is my middleware to check the session
function isLoggedIn(req, res, next) {
console.log("first auth");
// if user is authenticated in the session, carry on
if (req.isAuthenticated()) {
return next();
}
so when am trying to check iof am logged in or not i get the following from console
Deaire ==>17152 Executing (default): SELECT id, firstName,
lastName, phoneNumber, photo, token, deviceToken, osInfo,
actualLat, actualLng, cityId, countryId, status,
createdAt, updatedAt FROM users AS User WHERE User.id =
17152;

MongoStore, Passport-local - Sessions are not being stored in db

I have a Node.js Express App and I am trying to use MongoStore to save the sessions and Passport-local for authentication. The app is not storing sessions in db.sessions
app.js
var session = require("express-session");
var MongoStore = require("connect-mongo/es5")(session);
var passport = require('passport');
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false,
duration: 30 * 60 * 1000,
activeDuration: 5 * 60 * 1000,
store: new MongoStore({
url: MongoDB.MONGODB_URL
})
}));
app.use(passport.initialize());
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
db.users.findById(id, function(err, user){
if(!err) done(null, user);
else done(err, null);
});
});
localstrategy is implemented as follows. MongoDB is my own module which interacts with MongoDB.
passport.use('local', new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function (email, password, done) {
process.nextTick(function () {
MongoDB.collection("users").findOne({
email: email
}, function (error, doc) {
if (error) {
return done(error);
}
if (doc) {
if (doc.password === PasswordManager.encryptPassword(password)) {
return done(null, doc);
} else {
return done("Invalid Password", false);
}
}
});
});
}
));
Authentication Request.
As I am trying to use MongoStore sessions, I have passed the option - {session: false} to the req.LogIn function.
router.post('/login', function (req, res, next) {
passport.authenticate('local', function (err, user) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).send({
success: false,
error: "User not found!",
data: null
});
}
req.logIn(user, {session: false}, function (err) {
if (err) {
return next(err);
}
req.session.user = user;
return res.send({
success: true,
error: null,
data: user
});
})
})(req, res, next);
});

Resources