I'm trying to build a login system using express and passport.
As far as I know, I can use the req.user to access user id and correctly store their actions and req.isAuthenticated() would be true if Passport is working properly, however it isn't working.
For some reason, req.user is always undefined and req.isAuthenticated() is always false.
This is my app.js ->
const express = require('express');
const http = require('http');
const session = require('express-session');
const bodyParser = require('body-parser');
const passport = require('passport');
const route = require('./controllers/core'); **// CORE.JS**
const app = express();
app.set('view engine', 'ejs');
app.use('/css', express.static('css'));
app.use('/js', express.static('js'));
app.use('/themify', express.static('themify'));
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
//cookie: { secure: true }
}));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session());
app.use(route);
//core(app);
app.listen(3000);
And this is my core.js
const router = require('express').Router();
const passport = require('passport');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'pharmate',
dateStrings: 'date'
});
const urlencodedParser = bodyParser.urlencoded({ extended: false });
router.get('/index', function(req,res){
console.log(req.user);
});
router.post('/index', urlencodedParser, function(req,res){
var email = req.body.email;
var pass = req.body.password;
connection.query("SELECT `Pharmacy_ID`, `Email`, `Password` FROM `pharmacy` WHERE Email = ? AND Password = ?", [email, pass], function (error, results, fields) {
if (error) res.send(error);//throw error;
else{
if(results.length>0){
req.login(results[0], function(err){
res.redirect('index');
});
}
else{
res.redirect('login');
}
}
});
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
done(null, user);
});
module.exports = router;
Any help would be appreciated. Thanks in advance.
You should handle the authentication like:
app.post('/login',
passport.authenticate('local', {
successRedirect: '/secret',
failureRedirect: '/login',
})
);
Did you setup the passport local strategy ?
Related
I am using passport to implement a login function on my application. However, every time I try to authenticate the user, I cannot get passed the authentication and am redirected to the failure URL. I have confirmed that there is a user in the MongoDB database and the user supplied password is correct. However, I cannot get past the passport authentication. Can anyone please help me out ?
This is my index.js
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const path = require('path');
const ejsMate = require('ejs-mate');
const loginRoutes = require("./routes/login");
const User = require('./models/users');
const session = require('express-session');
const userRoutes = require('./routes/user');
const passport = require('passport');
const localStrategy = require('passport-local');
sessionConfig = {
name: "session",
secret: 'BetterSecret',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
expires: Date.now() + 604800000, //Date.NOW + No. of Miliseconds in the week
maxAge: 604800000
}
};
//Connection strings only beyond this line
mongoose.connect('mongodb://localhost:27017/myLoc').then(console.log("DB connected")).catch(error => handleError(error));
app.listen(5500, (req, res, next) => {
console.log("Connected");
});
//app.uses
app.use(express.urlencoded({ extended: true }));
app.use("/", loginRoutes);
app.use("/business", userRoutes);
app.engine('ejs', ejsMate);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views')); //setting up the views directory
app.use(express.static(path.join(__dirname, 'public'))); //public directory to serve static content
app.use(session(sessionConfig));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
This is the router for the login:
const express = require('express');
const router = express.Router();
const users = require('../controllers/users');
const passport = require('passport');
router.route('/login')
.get(users.renderLoginForm)
.post(passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }), users.login);
router.route('/register')
.get(users.renderRegisterForm)
.post(users.createNewUser);
module.exports = router;
and for the controller I just have a console.log for now
module.exports.login = (req, res, next) => {
console.log("I am here");
};
I'm using passport-local for authentication. When starting from login page I do redirect where I should if usr/pwd is correct and redirect back to login when it's not, but if add the authentication requirement to a page I'm always getting redirected to the login page.
app.js
var express = require('express');
var passport = require('passport');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var authRouter = require('./routes/auth');
var listsRouter = require('./routes/lists');
var app = express();
require('./boot/auth')();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.authenticate('session'));
app.use('/', indexRouter);
app.use('/', authRouter);
app.use('/lists', listsRouter);
module.exports = app;
boot/auth.js
var passport = require('passport');
var Strategy = require('passport-local');
module.exports = function () {
passport.use(new Strategy(function (username, password, cb) {
if (checkUsrPwd()) {
var user = {
id: '1',
username: 'my_user',
displayName: 'user name'
};
return cb(null, user);
} else {
return cb(null, false, {
message: 'Incorrect username or password.'
});
}
}));
passport.serializeUser(function (user, cb) {
process.nextTick(function () {
cb(null, {
id: user.id,
username: user.username
});
});
});
passport.deserializeUser(function (user, cb) {
process.nextTick(function () {
return cb(null, user);
});
});
};
routes/lists.js
const express = require('express');
const ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
const router = express.Router();
router.get("/list", ensureLoggedIn('/'), (req, res) => {
[...]
res.contentType = 'application/json';
res.render('list', {
userData: items
});
};
});
});
What did I miss?
I was missisng a line in my app.js
app.use(require('express-session')({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
After adding that everything is working fine.
I know that there are numerous posts already referring to the same problem, however, I couldn't find a solution for my case. Here is the relevant code for the issue :
users.js (route)
The login form is submits a POST request to this route.
var express = require('express');
var router = express.Router();
// Require controllers
var usersController = require('../../controllers/usersController');
/* POST login */
router.post('/login', usersController.loginAccount);
module.exports = router;
usersController.js
The passport authentication is handled here.
req.isAuthenticated() returns false here as well. However, successRedirect is executed, which should mean that the user was successfully authenticated.
'use strict';
var bodyParser = require('body-parser');
var mysql = require('mysql');
var bcrypt = require('bcryptjs');
var Client = require('../models/Client');
var passport = require('passport');
var Sequelize = require('sequelize');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
/* POST - Login */
module.exports.loginAccount = function (req, res, next) {
passport.authenticate('local', {
successRedirect: '../dashboard',
failureRedirect: '/users/login',
failureFlash: true
}) (req, res, next);
console.log("Exactly after authentication: " + req.isAuthenticated());
}
index.js (route)
Here, ensureAuthenticated always returns false
var express = require('express');
var router = express.Router();
// Require controllers
var indexController = require('../../controllers/indexController');
/* GET dashboard page */
router.get('/dashboard', ensureAuthenticated, indexController.dashboardPage);
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated())
{console.log("AUTHENTICATED"); return next();}
else{
console.log("NOT AUTHENTICATED");
req.flash('error_msg', 'Please log in to view this resource');
res.redirect('/users/login');
}
}
module.exports = router;
indexController.js
When submitting the login form, this code doesn't get executed, because ensureAuthenticated() is false.
'use strict';
var bodyParser = require('body-parser');
var mysql = require('mysql');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
/* GET - Dashboard page */
module.exports.dashboardPage = function(req, res) {
// console.log(req.user);
// console.log(req.isAuthenticated());
res.render('dashboard');
};
passport.js
const LocalStrategy = require('passport-local').Strategy;
const Sequelize = require('sequelize');
const bcrypt = require('bcryptjs');
// Load User Model
const Client = require('../models/Client');
module.exports = function(passport) {
passport.use(
new LocalStrategy({ usernameField: 'username'}, function(username, password, done) {
// Match User
Client.findOne({ where: {username: username} })
.then(function(user) {
if(!user) {
return done(null, false, { message: 'That username is not registered'});
}
// Match password
bcrypt.compare(password, user.password, function(err, isMatch) {
if(err) throw err;
if(isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Password incorrect'});
}
});
})
.catch(function(err) { console.log(err) });
})
)
passport.serializeUser(function(user, done) {
console.log('Serializing user');
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log('Deserializing user');
console.log('User ID:', id);
Client.findByPk(id)
.then(function(err, user) {
console.log('User ID:', id);
done(err, user);
});
});
}
All the required middleware is setup in the correct order (express-session -> passport.initialize -> passport.session). cookieParser and express-session are set with the same secret (which is otherwise a problem as other posts suggest).
app.js
var createError = require('http-errors');
var express = require('express');
var expressLayouts = require('express-ejs-layouts');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mysql = require('mysql');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var bodyParser = require('body-parser');
var cors = require('cors');
// Passport config
require('./config/passport')(passport);
var usersController = require('./controllers/usersController');
var indexRouter = require('./api/routes/index');
var usersRouter = require('./api/routes/users');
var roomsRouter = require('./api/routes/rooms');
var app = express();
app.use(cors());
// view engine setup
app.set('views', path.join(__dirname, 'views'));
// EJS
app.use(expressLayouts);
app.use(express.json());
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('secret'));
app.use(express.static(path.join(__dirname, 'public')));
// Express Session
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}));
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
In your app.js the routes need to be defined after the passpor middleware is set up.
For Example:
var createError = require('http-errors');
var express = require('express');
var expressLayouts = require('express-ejs-layouts');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mysql = require('mysql');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var bodyParser = require('body-parser');
var cors = require('cors');
// Passport config
require('./config/passport')(passport);
var usersController = require('./controllers/usersController');
var app = express();
app.use(cors());
// view engine setup
app.set('views', path.join(__dirname, 'views'));
// EJS
app.use(expressLayouts);
app.use(express.json());
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('secret'));
app.use(express.static(path.join(__dirname, 'public')));
// Express Session
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}));
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
var indexRouter = require('./api/routes/index');
var usersRouter = require('./api/routes/users');
var roomsRouter = require('./api/routes/rooms');
Try doing this and see the output
I have 2 modules
users
blogs
i have implemented users for login register with passport authentication . When i try to use current user data(req.user) in blog model it results 'undefined'.
i have share my code below
app.js
const express = require('express');
const app =express();
const path = require('path');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended : false }));
app.use(bodyParser.json());
const Users = require("./routes/Users");
const Blogs = require("./routes/Blog");
app.use("/users",Users);
app.use("/blogs",Blogs);
app.set('views',path.join(__dirname, 'views'));
app.set('view engine','ejs');
app.listen(3000, function() {
console.log('Server started...');
});
users.js
const passport = require('passport');
const express=require('express');
const users = express.Router();
const models = require('../models');
const User = models.users;
var cookieParser = require('cookie-parser');
const session = require('express-session');
users.use(cookieParser());
users.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}));
users.use(passport.initialize());
users.use(passport.session());
require('../config/passport.js')(passport, User);
users.post('/register',passport.authenticate('local-register', {
successRedirect: '/users/profile',
failureRedirect: '/users/register'
}
));
users.post('/login',passport.authenticate('local-login', {
session: true,
successRedirect: '/users/profile',
failureRedirect: '/users/profile'
}
));
module.exports =users;
blogs.js
const express = require('express');
const blogs = express.Router();
const blogModel = require('../models/blogs');
blogs.get('/',(req,res) =>{
console.log(req.user) // RESULTS UNDEFINED
res.send('Blog List');
});
passport.js
const bCrypt = require('bcryptjs');
const LocalStrategy = require('passport-local').Strategy;
module.exports = function(passport, user) {
const User = user;
passport.use('local-register', new LocalStrategy( { usernameField: 'email', passwordField: 'password', passReqToCallback: true },
function(req, email, password, done) {
... ....
}
));
passport.use('local-login', new LocalStrategy({ usernameField: 'email', passwordField: 'password', passReqToCallback: true },
function(req, email, password, done) {
..... .....
}
));
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
const User =user;
User.findById(id).then((user) =>{
if (user) {
done(null, user);
} else {
done(user.errors, null);
}
});
});
}
You are initiating passport (which handles req.user) only for Users router, this way only routes starting with /users will actually have access to req.user.
In order to use req.user inside the Blogs module, you need to initiate passport for the entire express app (instead of just the users router).
You would probably want to move the initialization to the app.js file
app.use(bodyParser.urlencoded({extended : false }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
I believe your problem is you are using multiple objects/instance of express packages and trying to pass from one to another. It won't work as expected. To make it working you should have multiple routes using the same express instance.
I've read similar questions, but I couldn't find a solution.
In my server.js file:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var passport = require('passport');
var cookieParser = require('cookie-parser');
var expressSession = require('express-session');
var passportHelp = require('./config/passport');
var flash = require('connect-flash');
app.use(express.static(__dirname + '/public'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.set('view engine', '.hbs');
app.set('views', path.join(__dirname, './app/views'))
app.use(expressSession({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
passportHelp(passport);
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(require('./app/controllers'));
app.listen(3000);
In ./app/controllers
var express = require('express');
var router = express.Router();
router.use(require('./signup'));
module.exports = router;
In ./controllers/signup
var express = require('express');
var passport = require('passport');
var router = express.Router();
router.get('/signup', function(req, res) {
res.render('signup');
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true,
}));
module.exports = router;
Finally, in ./config/passport
var LocalStrategy = require('passport-local').Strategy;
var User = require('../app/models/user');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
console.log(req.body.username);
console.log(req.body.password); //successfully logs all of these 3
console.log(req.body.email);
process.nextTick(function() {
User.findOne({ 'username' : username }, function(err, user) {
if (err) {
return done(err);
}
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
}
else {
var newUser = new User;
//filling new user data here
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
I end up with strange behavior. Sometimes POST has no problem, sometimes I get cannot POST /signup, but the result is still saved into the database.
I've tried switching some lines in server.js file, but without result. As I've read, when I require passport in controller/signup, it should be the same 'passport' object which I 'initialized' in server.js, so I dont end up working with a fresh passport object. Am I right?
In case someone faces the same problem.
The reason I got the error, but the save into the database was successful was that I have commented that line: successRedirect