I'm trying to get a handle on user authentication with PassportJS, and I cannot get it to work my database setup.
I'm using MongoDB without Mongoose, and I can't get the LocalStrategy module to work.
Hopefully my database queries aren't too cumbersome to read.
Local Strategy:
passport.use(new LocalStrategy(
function(username, password, done) {
//Fire up database
mongo.connect("mongodb://localhost:27017/formulas", function(e, db) {
if (e) {return next(e);}
var col = db.collection("users");
//Do a database query to find a record by username
col.findOne({"username": username}, function(err, user){
if (err) { return done(err);}
if(!user) {
return done(null, false, { message: "Please check your log in credentials." });
}
//if it exists call done() object with user information
bcrypt.compare(password, user.password, function(err, res){
if (err) throw err;
if (res == true) {
return done(null, {username: username, password: password});
} else {
return done(null, false, { message: "Invalid password."});
}
});
});
});
}));
I call passport.authenticate() like this:
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect:'/about',failureFlash: false}),
function(req, res){
console.log(req.body);
console.log(req.user);
console.log("The user was logged");
});
SerializeUser and deserializeUser look like this:
passport.serializeUser(function(user, done) {
done(null, user.username);
});
passport.deserializeUser(function(id, done) {
mongo.connect("mongodb://localhost:27017/formulas", function(e, db){
if (e) {return next(e);}
var col = db.collection("users");
col.findOne({"username": id}, function(err, user){
done(err, {"username": id});
});
});
});
When I call app.post(/login) I'm taken directly to /about and nothing is logged to the console so I'm not quite sure what's going wrong.
Advice on what to fix or how to troubleshoot is greatly appreciated.
Firstly when u serialize user object , then in deserialize also whole user object must be passed.
Consider the example below.
For routes :
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
req.session.user = req.user;
return res.redirect('/home');
});
})(req, res, next);
});
For passport.js , place the localstrategy and passport in same folder
var passport = require('passport'),
session = require('express-session');
var local = require('./localstrategy.js');
module.exports = function (app) {
app.use(session({
secret: 'Site visit',
resave: true,
saveUninitialized: true,
cookie: { secure: false }
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done){
done(null, user);
});
passport.deserializeUser(function(user, done){
done(null, user);
});
local();
};
For local strategy :
'use strict';
var passport = require('passport'),
local = require('passport-local').Strategy;
var user;
// path where the db.js is placed
var db = require('./../db.js');
var ObjectId = db.getObjectID();
var bcrypt = require('bcrypt');
module.exports = function(){
passport.use(new local({
usernameField : 'username',
passwordField : 'password'
}, function(username, password, done){
var collection = db.getDb().collection('users');
collection.findOne({
username: username,
}, function (err, result) {
if(result == null){
cb(null, false);
}else {
bcrypt.compare(password, result.password, function (err, passRes) {
if (passRes == true) {
user = user;
done(err, user);
}else{
done(null, false, { message : 'Invalid Password'});
}
});
}
});
}));
};
Related
I created a folder config and i created passport.js file inside it, that holds all the configuration passport module when i tried to run my code i got this error TypeError: Cannot read property 'use' of undefined referring to this line of code passport.use(new LocalStrategy(function(username, password, done) {
passport.js file :
var express = require('express');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../server/model/userModel');
const bcrypt = require('bcrypt');
var passport = require('passport');
module.exports = function(passport) {
// Local Strategy
passport.use(new LocalStrategy(function(username, password, done) {
// Match Username
let query = { username: username };
User.findOne(query, function(err, user) {
/*
if (err) throw err;
if (!user) {
return done(null, false, { message: 'No user found' });
}
*/
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
// 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: 'Wrong password' });
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
You use two different references for the same name.
var passport = require('passport');
Here, you defined the passport variable.
module.exports = function(passport) {
Here, you define the parameter name as passport. Using passport in this context will refer to the parameter
passport.use(...
Calling on the parameter's use method instead of the passport.use method from the defined variable. Consider changing the function parameter name to something other than passport, maybe _passport?
module.exports = function(passport) {
//to
module.exports = function(_passport) {
Have you initialised:
app.use(passport.initialize());
app.use(passport.session());
To use Passport in an Express or Connect-based application, configure it with the required passport.initialize() middleware. If your application uses persistent login sessions (recommended, but not required), passport.session() middleware must also be used.
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); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
https://github.com/jaredhanson/passport
I have a problem with passport.js, when I try to log into my account, I get an error: Error: Unknown authentication strategy "local-login". ". What's wrong with my code, thank you.
config/Passport.js
var passport = require('passport');
var request = require('request');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user'); // model User
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-login', new LocalStrategy(function(username, password,
done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { msg: "Username" + username + "not found."
});
}
user.comparePassword(password, function(err, isMatch) {
if (err) { return done(err); }
// Make sure the user has been verified
if (isMatch) {
return done(null, user);
}
return done(null, false, { msg: 'Invalid email or password.' });
});
});
}));
app.js
var session = require('express-session');
var passport = require('passport');
app.use(session({
secret: config.secret,
resave: true,
saveUninitialized: true,
cookie: { maxAge: 1*15*1000 }
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req, res, next) {
res.locals.user = req.user;
next();
});
routes/authRoutes.js
app.post('/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) { return next(err); }
if (!user) {
return res.redirect('/login');
}
req.login(user, function(err) {
if (err) { return next(err); }
res.redirect('/');
});
})(req, res, next);
});
It must be 'local' instead of 'local-login'
module.exports.login_post = passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/',
failureFlash: true
});
I Use MySQL. It's the complete code:
passport.use(new LocalStrategy({
passReqToCallback: true
}, function(req, username, password, done) {
pool.query("SELECT * FROM user WHERE username = ?",[username], function(err, rows, fields) {
if (err) throw err;
console.log('checked');
if(!isExist(username) || !isExist(password)){
return done(null, false, req.flash('message_err', 'Username and password cant be emptied!.'));
}
if (!rows[0]) {
return done(null, false, req.flash('message_err', 'Oops! Username or password didnt match.'));
}
if (!bcrypt.compareSync(password, rows[0].password)) {
return done(null, false, req.flash('message_err', 'Oops! Username/password didnt match.'));
}
return done(null, rows[0]);
});
}));
passport.deserializeUser(function(user, done) {
console.log('user : ' + user);
pool.query("SELECT * FROM user WHERE username = ?", [user], function(err, rows, fields) {
if(err) throw err;
console.log('deserialized');
done(err, rows[0]);
});
});
//serialize and deserialize passport
passport.serializeUser(function(req, user, done) {
console.log('serialized');
done(null, user.username, req.flash('message_success', 'Welcome, '+user.username + "!"));
});
module.exports.login_post = passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/',
failureFlash: true
});
After I login to my application, passport(local strategy) middleware matches the password to the one stored in database and routes me to the user page but it does not starts the session, due to which I am not able to authenticate post and get request for that user.
After playing around with code I found out that, passport.serializeUser and passport.deserializeUser are never called, I used console.log() to check the same.
I read the passport control flow from this link and found out that after password is matched and user is passed, the middleware calls req.login which further calls passport.serializeUser, I think in my case the req.login is never called because of which session is not maintained.
I have tried everything but am not able to figure out where I am going wrong.
This is my password Config :-
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/userModel');
module.exports = function(passport){
passport.serializeUser(function(user, done) {
console.log("serialize");
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
console.log("deserialize");
User.getUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(function(username, password, done){
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
console.log("not user");
return done(null, false);
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) return done(err);
if(isMatch){
console.log("pass match");
return done(null, user);
} else {
console.log("invalid pass ");
return done(null, false);
}
});
});
}));
}
I always get the response "pass match" if I submit the correct user info in the login page.
This is login page where I have setup Authentication request
var LocalStrategy = require('passport-local').Strategy;
var passportAuth = require('../config/passport');
module.exports = function(app,bodyParser,passport){
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.post('/api/loginAuth', (req,res,next)=> {
passport.authenticate('local', function(err, user, info ) {
if (err) {
console.log("inside error");
return next(err);
}
if (!user) {
console.log("No user");
res.status(401).send("not user");
} else {
console.log("verified user");
res.json(user);
}
})(req, res, next);
});
passportAuth(passport);
}
Passport and session setup in my app.js
var session = require('express-session');
var passport = require('passport');
// Handle Sessions
app.use(session({
secret:'secret',
saveUninitialized: true,
resave: true,
}));
// Passport
app.use(passport.initialize());
app.use(passport.session());
This is my angularjs Post request for authentication
$http({
method: 'POST',
url: '/api/loginAuth',
data: $scope.userinfo,
withCredentials: true
}).success (
function(response){
var message = '<strong>'+response.name+'</strong> Successfully logged in!! ';
sharedDataService.setMessage(message);
sharedDataService.setProperty(response.name);
$state.go('todo', {username: response.username});
});
Add this code to else part of app.post
req.logIn(user, function(err) {
if (err) { return res.send(err); }
res.json(user);
});
Like this
app.post('/api/loginAuth', (req,res,next)=> {
passport.authenticate('local', function(err, user, info ) {
if (err) {
console.log("inside error");
return next(err);
}
if (!user) {
console.log("No user");
res.status(401).send("not user");
} else {
req.logIn(user, function(err) {
if (err) { return res.send(err); }
res.json(user);
});
}
})(req, res, next);
});
My model looks like this, but when I try use verifyPassword, it says TypeError: user.verifyPassword is not a function
var passport = require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;
var User = require('../models/user');
passport.use(new BasicStrategy(
function(username, password, callback) {
User.findOne({ username: username }, function (err, user) {
if (err) { return callback(err); }
// No user found with that username
if (!user) { return callback(null, false); }
// Make sure the password is correct
// Error comind at this point
user.verifyPassword(password, function(err, isMatch) {
if (err) { return callback(err); }
// Password did not match
if (!isMatch) { return callback(null, false); }
// Success scenario
return callback(null, user);
});
});
}
));
Try to use User.verifyPassword function
But for more correct answer show your User model
You should have in your User schema something like:
// I am use bctypt, but you need your comparer function
userSchema.methods.verifyPassword = function(password, callback) {
callback(err, bcrypt.compareSync(password, this.password));
};
I know i am late but you can do something like this,
passport.use(
'local',
new LocalStrategy(function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false);
}
if (user.password != password) {
return done(null, false);
}
return done(null, user);
});
})
);
Reference : https://github.com/sikandar114/node-auth-pass-local/blob/master/config/passport.js
Since the data is sent by post method, express is not able to parse data because body-parser middleware has been omitted from express due to some issues. Hence you must add it manually.Import body-parser:
npm install body-parser
Add these lines to your code.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
Also define these 2 functions.
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
Try using passport.use(new LocalStrategy(User.authenticate()));
I'm using Express (v4.11.2) with Passport in order to support multiple providers (local, facebook, twitter and google) for access to the web app I'm building. As a backend I'm using mysql. For now I have two local strategies: local-signup and local-signin. The issue I'm experiencing is that the req.session.passport and req.user are always empty and that, in fact, serializeUser and deserializeUser are never being called.
Here is the setup of express and passport:
var bodyParser = require('body-parser');
var session = require('express-session');
var MemoryStore = session.MemoryStore;
var _ = require('underscore');
var passport = require('passport');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
key: 'KEY',
secret: 'SECRET331156%^!fafsdaasd',
store: new MemoryStore({reapInterval: 60000 * 10}),
saveUninitialized: true,
resave: false
}));
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport); // pass passport for configuration
and here is the passport file with authentication strategies:
module.exports = function (passport) {
passport.serializeUser(function (user, done) {
logger.info('SERIALIZE USER');
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
logger.info('DESEIRALIZE USER!');
mysqllib.getConnection(function (err, connection) {
if (err) {
done(err);
}
var sql = "SELECT * FROM users WHERE idusers = ?";
logger.info('sql: ' + sql);
connection.query(sql, [id], function (err, rows) {
connection.release();
var user = {};
user.id = rows[0].idusers;
done(err, user.id);
});
});
});
passport.use('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function (req, email, password, done) {
logger.info('CALLING local-signup');
var firstname = req.body.firstname;
var lastname = req.body.lastname;
var role = req.body.role;
mysqllib.getConnection(function (err, connection) {
var sql = "INSERT INTO users VALUES(0, ?, ?, ?, ?, null, ?, 0, null, null, null, null, null, null, 0, 0)";
logger.info('sql: ' + sql);
connection.query(sql, [email, password, firstname, lastname, role], function (err, rows) {
connection.release();
if (err) {
if (err.code == 'ER_DUP_ENTRY') {
logger.info('er_dup_entry');
return done(err);
} else {
logger.info('general err');
return done(err);
}
} else {
logger.info('everything is OK!');
var user = {};
user.id = rows.insertId;
req.session.user_auth = user.id;
return done(null, user);
}
});
});
}));
passport.use(
'local-login',
new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function (req, email, password, done) {
mysqllib.getConnection(function (err, connection) {
if (err) {
logger.info('getConnection: ' + err);
return done(err);
}
var sql = "SELECT idusers, first_name, last_name, email, phone, dob, address, role, photo1, photo2, photo3, photo4, phonevalidated, uservalidated FROM users WHERE email = " + connection.escape(email) + " AND password = " + connection.escape(password);
connection.query(sql, function (err, rows) {
connection.release();
if (err) {
logger.error("select user", err);
return done(err);
} else if (rows.length) {
var user = rows[0];
user.id = rows[0].idusers;
return done(null, user);
} else {
logger.warn('Incorrect Login credentials, username: ' + email + ' password: ' + password);
return done(null, false, {message: 'unauthorized'});
}
});
});
})
);
};
and, for last, here is how I'm using the strategies in express routes:
app.post('/login', function (req, res, next) {
passport.authenticate('local-login', function (err, user, info) {
if (err) {
mysend(res, 500, 'Ups. Something broke!');
} else if (info) {
mysend(res, 401, 'unauthorized');
} else {
mysend(res, 200, JSON.stringify(user));
logger.info(req.user);
logger.info(req.session);
}
})(req, res, next);
});
Everything works fine, even in a strategy I can set the value of user's id in the session like this:
req.session.user_id = user.id
and continue to use it manually but I really don't get why serializeUser and deserializeUser aren't being called.
You need to call req.login() in custom callback which will then call serializeUser and set the user object to the session:
app.post('/login', function (req, res, next) {
passport.authenticate('local-login', function (err, user, info) {
if (err) {
mysend(res, 500, 'Ups. Something broke!');
} else if (info) {
mysend(res, 401, 'unauthorized');
} else {
req.login(user, function(err) {
if (err) {
mysend(res, 500, 'Ups.');
} else {
mysend(res, 200, JSON.stringify(user));
}
}
}
})(req, res, next);
});