NodeJS Express Passport - req.user is undefined - node.js

I'm testing authentication in small app using express+passport and trying to do it without sessions. So user have to provide username and password for every action.
After authorization (passport.authenticate()) in next middleware request.user is undefined, but passport faq says that "If authentication succeeds, the next handler will be invoked and the req.user property will be set to the authenticated user."
What is wrong here?
listing
const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const app = express();
app.use(express.json());
app.use(express.urlencoded({
extended: true
}));
passport.use('login',
new LocalStrategy({
session: false,
passReqToCallback: true
},
(req, username, password, done) => {
// passport.use(new LocalStrategy((username, password, done) => {
console.log(' In passport.use(new LocalStrategy...)');
console.log('req.body = ', req.body);
console.log('req.user = ', req.user);
const user = {
username: username,
password: password,
};
if (user.username === 'Petr' && user.password === '123') {
console.log('Username and password OK');
return done(null, user);
}
return done(null, false, {
message: 'Wrong username or password!'
});
},
),
);
app.post('/', passport.authenticate('login', {
session: false,
successRedirect: '/success',
failureRedirect: '/failure',
}));
app.use('/', (req, res, next) => {
console.log(' In app.use /');
console.log('req.body = ', req.body);
console.log('req.user = ', req.user); //HERE req.user is undefined!!!
next();
});
app.use('/', (req, res, next) => {
console.log('Request at /');
next();
});
app.use('/success', (req, res, next) => {
res.send('success');
next();
});
app.use('/failure', (req, res, next) => {
res.send('failure');
next();
});
app.listen(8000, () => {
console.log('Server "Test" starts at port 8000');
});

Have you set up session state for your app? You have to add it like this...
app.use(session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());

Related

Bad Request in Node Js using passport Js

I am trying to build a registration and login page using passport-local-mongoose.
When I click on submit signup button I get an error which says bad request.
I am getting "Bad Request" while registering, but the details are being stored in MongoDB. Not sure where I am making a mistake.
Please help me out.
Here is my register POST API.
let express = require('express');
let mongoose = require('mongoose');
const passport = require('passport');
const LocalStrategy = require('passport-local');
const passportLocalMongoose = require('passport-local-mongoose');
var expressValidator = require('express-validator');
const bodyParser = require('body-parser')
const { check, validationResult } = require('express-validator');
const Admin = require('../models/admin-model');
let router = express.Router();
const app = express();
//Creating a Secret Key to Hash Password
router.use(require('cookie-session')({
secret: 'jdkjhLGUL#^&%^%(*)&^%#!gkjh', // Encode/Decore Session
resave: false,
saveUninitialized: false
}));
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
}, Admin.authenticate()));
//Encrypting and Decrypting the Password for Security
passport.serializeUser(Admin.serializeUser()); //session Encoding
passport.deserializeUser(Admin.deserializeUser());
// passport.use(new LocalStrategy(Admin.authenticate()));
//Setting the View Engine to take EJS Pages
app.set('view engine', "ejs");
app.set('views', "./views")
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(__dirname + '/public'));
mongoose.connect("mongodb://localhost:27017/node-auth-db", { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Connected to node-auth-db successfully....!'))
.catch(err => console.log(err))
router.get('/', (req, res) => {
res.render('home');
});
router.get('/login', (req, res) => {
res.render('signin');
});
router.post('/login', passport.authenticate("local", {
successRedirect: '/admin/addnews',
failureRedirect: '/login'
}));
//Registration
router.get('/register', (req, res) => {
res.render('signup');
});
router.post('/register', (req, res) => {
Admin.findOne({ username: req.body.email }, (err, result) => {
if (err) throw err;
if (!result) {
Admin.register(new Admin({ name: req.body.name, username: req.body.email }),
req.body.password, function (err, admin) {
if (err) throw err;
passport.authenticate("local")(req, res, function () {
res.redirect('/admin/login');
})
}
)
}
else {
res.redirect('/admin/register');
}
});
});
//Add News
router.get('/addnews', isLoggedIn, (req, res) => {
res.render('addnews');
});
router.post('/addnews', (req, res) => {
News.create(req.body, (err, data) => {
if (err) throw err;
const htmlMsg = encodeURIComponent('Added News DONE !');
res.redirect('/admin/addnews');
})
});
//Creating a Authentication Token to secure the logging and Logout.
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/admin/login');
}
router.get('/logout', (req, res) => {
req.logOut();
res.redirect('/admin');
});
module.exports = router;[]
Might be the issue is here you are passing req.body.password outside admin module
Admin.register(new Admin({ name: req.body.name, username: req.body.email, req.body.password}), function (err, admin) {
if (err) throw err;
passport.authenticate("local")(req, res, function () {
res.redirect('/admin/login');
})
}
)

Setting up passport for the first time. isAuthenticated() always returning false

I'm working through a learning module on authentication and security and I'm trying to get passport up and running but I seem to be having trouble. The code included below all works as you'd expect, except that when users are redirected from the /register post route to the /secrets route, they are not authenticated, in spite of .register() having worked (otherwise the logic in the route would have redirected me back to the /register get route instead of the login page via the secrets route).
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const ejs = require("ejs");
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static("public"));
app.set("view engine", "ejs");
app.use(
session({
secret: "Our little secret.",
resave: false,
saveUninitialized: false
})
);
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost:27017/userDB", { useNewUrlParser: true });
mongoose.set("useCreateIndex", true);
const userSchema = new mongoose.Schema({
username: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
const Users = new mongoose.model("Users", userSchema);
passport.serializeUser(Users.serializeUser());
passport.deserializeUser(Users.deserializeUser());
app.listen(3000, (req, res) => {
console.log("Listening on port 3000.");
});
app.get("/", (req, res) => {
res.render("home");
});
app.get("/login", (req, res) => {
res.render("login");
});
app.get("/register", (req, res) => {
res.render("register");
});
app.get("/secrets", (req, res) => {
console.log(req.isAuthenticated())
if (req.isAuthenticated()) {
res.render("secrets");
} else {
res.redirect("/login");
}
});
app.post("/register", (req, res) => {
console.log(req.body.username)
console.log(req.body.password)
Users.register(
{ username: req.body.username },
req.body.password,
(error, user) => {
if (error) {
console.log('there was an error: ', error);
res.redirect("/register");
} else {
passport.authenticate("local")(req, res, () => { //////////////not authenticating
res.redirect("/secrets");
});
}
}
);
});
app.post("/login", (req, res) => {});
any help figuring out why isAuthenticaed() is returning false would be greatly appreciated. thank you :)
You have to define your local strategy :
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
here it has queried User information from the database ( Mongodb for instance) in case of successful response it will pass.

Node.js auth page with passport-local and bcryptjs

I have a basic login auth page but whenever i try and login the page just reloads,
I'm relatively new to this and really need help.
server.js👇
const express = require("express");
const fs = require("fs");
const path = require("path");
const passport = require("passport");
const session = require("express-session");
const initializePasspost = require("./passport-config");
const flash = require("express-flash");
const bcrypt = require("bcryptjs");
initializePasspost(
passport,
email => users.find(user => user.email === email),
id => users.find(user => user.id === id)
);
let data = fs.readFileSync("./files/users.json");
let userData = JSON.parse(data);
app.set("view-engine", "ejs");
app.use(express.urlencoded({ extended: false }));
app.use("/assets", express.static(path.join(__dirname, "/assets")));
app.use("/script", express.static(path.join(__dirname, "/script")));
app.use(flash());
app.use(
session({
secret: "woff",
resave: false,
saveUninitialized: false
})
);
app.use(passport.initialize());
app.use(passport.session());
// Middleware
const checkAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect("/admin");
};
const checkNotAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return res.redirect("/");
}
next();
};
app.get("/test", checkAuthenticated, (req, res) => res.render("test.ejs"));
app.get("/register", checkNotAuthenticated, (req, res) =>
res.render("register.ejs")
);
app.post(
"/adminLogin",
passport.authenticate("local", {
successRedirect: "/test",
failureRedirect: "/adminLogin",
failureFlash: true
}),
(req, res) => {}
);
const PORT = process.env.PORT || 3000;
app.listen(PORT, err => {
console.log(`Server Running at port: ${PORT}`);
});
I know im not the best or optimal coder, but i need help.
passport-config.js👇
const bcrypt = require("bcryptjs");
const LocalStrategy = require("passport-local").Strategy;
const initialize = (passport, getUserByEmail, getUserById) => {
const authenticateUser = async (email, password, done) => {
const user = getUserByEmail(email);
if (user == null) {
return done(null, false, { message: "No user with that email" });
}
try {
if (bcrypt.compareSync(password, user.password)) {
return done(null, user);
} else {
return done(null, false, { message: "password Incorrect" });
}
} catch (e) {
return done(e);
}
};
passport.use(new LocalStrategy({ usernameField: "email" }, authenticateUser));
passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser((id, done) => done(null, getUserById(id)));
};
module.exports = initialize;
I would have installed bcrypt but there was a problem installing it so I opted for bcryptjs.
I got some of the code from a youtube tutorial.
I don't know what to do. Please help. I'm stuck on this for more than a week.

How to make signup function in nodejs using passportjs?

I am trying to make a signup and signin app in node.js. I am using passport.js for authentication purpose.
My main problem here is whenever i submit my signup form with valid form data, its automatically log user in. Other functions are working properly. Login works perfectly but whenever i submit signup form it submits without any errors and shows successful message too. But main drawback is along with singup it also log user in which i don`t want.
Here is my code
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
const validator = require('express-validator');
const passport = require('passport');
const expressHbs = require('express-handlebars');
const flash = require('connect-flash');
const session = require('express-session');
const mongoose = require('mongoose');
const configDB = require('./config/database.js');
//db configuration
mongoose.connect(configDB.url, (err) => {
if(err) {
console.log('Error connecting to databse');
} else {
console.log('Connection Successful');
}
});
require('./config/passport');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.engine('.hbs', expressHbs({defaultLayout: 'layout', extname: '.hbs'}));
app.set('view engine', '.hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(validator());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'node_modules')));
//required for passport
app.use(session({
secret: 'mysecret',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) => {
res.locals.login = req.isAuthenticated();
res.locals.session = req.session;
next();
});
app.use('/users', users);
app.use('/', index);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
passport.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../models/user');
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, (req, email, password, done) => {
var fullname = req.body.name;
var address = req.body.address;
req.checkBody('name', 'Name is Required').notEmpty();
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Invalid password').notEmpty().isLength({ min: 4 });
var errors = req.validationErrors();
if (errors) {
var messages = [];
errors.forEach((error) => {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({ 'email': email }, (err, user) => {
if (err) {
return done(err);
}
if (user) {
return done(null, false, {message: 'That email is already taken.'});
} else {
var newUser = new User();
newUser.fullname = fullname;
newUser.email = email;
newUser.password = newUser.encryptPassword(password);
newUser.address = address;
newUser.isAdmin = false;
//saving the user
newUser.save((err) => {
if (err) {
return done(err);
}
return done(null, newUser, req.flash('info', 'Signup Completed, pleases login to continue'));
});
}
});
}));
passport.use('local-signin', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, (req, email, password, done) =>{
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Invalid password').notEmpty().isLength({ min: 4 });
var errors = req.validationErrors();
if (errors) {
var messages = [];
errors.forEach((error) => {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email': email}, (err, user) => {
if(err) {
return done(err);
}
if(!user) {
return done(null, false, {message: 'No User Found'});
}
if(!user.validPassword(password)) {
return done(null, false, {message: "Wrong Password"});
}
return done(null, user);
});
}));
user.js
var express = require('express');
var router = express.Router();
const passport = require('passport');
const User = require('../models/user');
/* GET users listing. */
router.get('/admin/dashboard', isLoggedIn, isAdmin, (req, res) => {
var user = req.user;
User.find({}, (err, users) => {
if(err) {
throw err;
} else {
res.render('admin/dashboard', {
successMsg: 'Hello' + ' ' + user.fullname,
users: users
});
}
});
});
//router.use('/', notLoggedIn, (req, res, next) => {
// next();
//});
router.get('/login', (req, res) => {
var messages = req.flash('error');
var infoMsg = req.flash('info');
res.render('users/login', { infoMsg: infoMsg, messages: messages, hasErrors: messages.length > 0 });
});
router.post('/login', passport.authenticate('local-signin', {// successRedirect: '/users/profile',
failureRedirect: '/users/login',
failureFlash: true
}), (req, res, next) => {
user = req.user;
role = user.isAdmin;
if(role) {
return res.redirect('/users/admin/dashboard');
} else {
return res.redirect('/users/profile');
}
});
router.get('/signup', (req, res, next) => {
var messages = req.flash('error');
res.render('users/signup', { messages: messages, hasErrors: messages.length > 0 });
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/users/login',
failureRedirect: '/users/signup',
failureFlash: true
}));
router.get('/profile', isLoggedIn, (req, res) => {
var user = req.user;
var role = user.isAdmin;
res.render('users/profile', {
user: user,
role: role,
successMsg: 'Welcome' + ' ' + user.fullname
});
});
router.get('/logout', isLoggedIn, (req, res, next) => {
req.logout();
res.redirect('/users/login');
});
//route middleware to make sure a use is logged in
function isLoggedIn(req, res, next) {
//if user is authenticated in the session, carry on
if(req.isAuthenticated()) {
return next();
}
res.redirect('/users/login');
}
function isAdmin(req, res, next) {
var user = req.user;
if(user.isAdmin == true) {
return next();
}
res.redirect('/users/profile');
}
function notLoggedIn(req, res, next) {
if(!req.isAuthenticated()) {
return next();
}
res.redirect('/');
}
module.exports = router;
You can use session configuration as per passport documentation
.post(passport.authenticate('local-signup', {
successRedirect: '/users/login',
failureRedirect: '/users/signup',
badRequestMessage: "You must fill in all of the form fields.",
failureFlash: true, // allow flash,
session: false // prevent auto-login
})
or you can give a callback to passport call and prevent session storing so it will not perform login
router.post('/signup', function(req, res, next) {
passport.authenticate('local-signup', function(err, user) {
if (err) { return next(err) }
if (!user) { return res.redirect('/users/signup') }
res.redirect('/users/login');
})(req, res, next);
});

passport.js session lost after redirect

I am trying to integrate passport into my node.js app.
app.js file
const app = express();
app.set('view engine', 'pug');
app.use('/libs', express.static('node_modules'));
require('../config/auth.config')(app, data, passport);
app.use((req, res, next) => {
res.locals.user = req.user;
next();
});
app.get('/', (req, res) => {
// those objects are populated correctly after redirect from auth middleware
console.log(req.session)
console.log(req.user)
return res.render('home');
});
app.get('/login', console.log(req.user);
// req.user is undefined here
if (req.user) {
return res.redirect('/');
}
return res.render('login'););
app.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
}));
auth.config.js
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const LocalStrategy = require('passport-local');
const MongoStore = require('connect-mongo')(session);
const config = require('./config');
const configAuth = (app, {
users
}, passport, db) => {
app.use(cookieParser('Purple Unicorn'));
app.use(bodyParser.urlencoded({
extended: true,
}));
app.use(bodyParser.json());
app.use(session({
store: new MongoStore({
url: config.connectionString
}),
secret: 'Purple Unicorn',
resave: true,
saveUninitialized: true,
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy((username, password, done) => {
return users.login(username, password)
.then((user) => {
if (user) {
return done(null, user);
}
return done(null, false);
});
}));
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
users.getUserById(id)
.then((user) => {
console.log(user);
if (user) {
done(null, user);
}
done(null, false);
});
});
app.use((req, res, next) => {
res.locals = {
user: req.user,
};
next();
});
};
module.exports = configAuth;
The data object is working correctly.
After the post request on /login with correct data, I am redirected to / where console.log(req.user) prints the correct user. It is also added in the req.session object.
After I follow a link to /login, it should redirect me after the check for req.user but returns undefined. Sessions in mongo are stored correctly.
It seems passport is not saving the session correctly.
The problem is in your deserializeUser method where you always run done callback twice. In if statement you should use return done(null, user); to get out from function;

Resources