I'm trying to build a user authentication system into my Node app with Passport.js. When I try to sign up as a new user, it seems to work fine. But when I try logging in, the command prompt gives me this:
throw er; // Unhandled 'error' event
^
TypeError: done is not a function
at C:\spectray\config\passport.js:55:22
at C:\spectray\node_modules\mongoose\lib\model.js:3419:16
at C:\spectray\node_modules\kareem\index.js:212:48
at C:\spectray\node_modules\kareem\index.js:127:16
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
Here's my passport.js file:
var passport = require('passport'), LocalStrategy = require('passport-local').Strategy;
var User = require('../app/models/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-signup', new LocalStrategy({
passReqToCallback : true
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email' : email}, 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();
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
passport.use(new LocalStrategy({
passReqToCallback : true
},
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);
});
}
));
And here's my server.js file:
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var flash = require('connect-flash');
var db = require('./config/database.js');
var favicon = require('serve-favicon');
app.use(favicon(__dirname + '/public/imgs/favicon.ico'));
mongoose.Promise = global.Promise;
mongoose.connect(db.url);
require('./config/passport');
app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.set('view engine', 'ejs');
app.use(session({ secret: 'penniesfromheaven', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(express.static(__dirname + '/public'));
require('./app/routes.js')(app, passport);
app.listen(port);
console.log('The magic happens on port ' + port);
I tried deleting my node_modules folder and running npm install, but this error still shows up. What am I doing wrong?
Because you are setting the passReqToCallback option to true in the LocalStrategy constructor, your callback function gets called with these arguments: (req, username, password, done), but your function is accepting (username, password, done), which is why the arguments are getting assigned to the wrong parameters (and thus why done isn't a function as the error message says). To fix this, try removing the passReqToCallback option, like this:
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);
});
}));
Or, if you decide later that you need the req in your LocalStrategy, then add the parameter to the function, like this:
passport.use(new LocalStrategy({
passReqToCallback : true
},
function(req, 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);
});
}
));
Related
I'm trying to create an application that utilizes a registration and login functionality. I have completed the registration portion where all the information (Email and Password) is successfully passed and saved into a MySQL database.
Problem: My issue now is that when I put in any existing credential and email, the application will hang and refuse to redirect the user to a new page. On the bottom of my browser, it will say "Waiting for localhost...". If I leave the page up for too long, it'll eventually lead to an error page with the words "This page isn’t working. localhost didn’t send any data. ERR_EMPTY_RESPONSE".
I tried console logging for any errors but was unable to identify any causes/errors. I did ensure that the information I inputted is properly being compared to the values in the database table and that the redirection to the page is functioning. I also tried rewriting my code in multiple ways but ended up encountering the same issue.
Below is my passport.js file:
var LocalStrategy = require('passport-local').Strategy;
// Load User model
const User = require('../models/User');
// Reference: http://www.passportjs.org/docs/
module.exports = function (passport) {
passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({ which: { email: email } })
.then(user => {
// Check if Email exists in database
if (!user) {
return done(null, false, {
message: "Email is not registered."
});
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (password != user.password) {
return done(null, false, { message: 'Password is incorrect.' });
} else {
return done(null, user);
}
})
.catch(err => console.log(err));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
// Find by Primary Key
User.findByPk(id, function (err, user) {
console.log(user);
done(err, user);
});
});
}
Below is my app.js (server) file:
var express = require('express')
var expressLayouts = require('express-ejs-layouts');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var app = express();
// Embedded JavaScript (EJS)
app.use(expressLayouts);
app.set('view engine', 'ejs');
// Express Session
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false
}));
// Bodyparser
app.use(express.urlencoded({ extended: false }));
// Passport
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
// Connect flash for notification messages
app.use(flash());
// Global Variables to define specific notification messages
app.use((req, res, next) => {
// Notification for Registration Page
res.locals.success_msg = req.flash('success_msg')
res.locals.error_msg = req.flash('error_msg');
// Notification for Passport Login Verification
res.locals.error = req.flash('error');
next();
});
// Routes
app.use('/', require('./routes/index'));
// Login/Register Endpoints routes (ex. /users/login)
app.use('/users', require('./routes/users'));
// Image
//app.use(express.static('./public'));
var port = process.env.PORT || 8026;
app.listen(port);
console.log('Server Running');
console.log("Port: " + port);
Below is my function to handle the login and redirection:
router.post('/login', (req, res, next) => {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
Please let me know if you need any other information. Thank you!
I think this could be a problem. On passport.use , if an error occurred, you are not returning anything.
passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({ which: { email: email } })
.then(user => {
// Check if Email exists in database
if (!user) {
return done(null, false, {
message: "Email is not registered."
});
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (password != user.password) {
return done(null, false, { message: 'Password is incorrect.' });
} else {
return done(null, user);
}
})
.catch(err =>{
console.log(err));
return done(null, false, { message: 'Internal Server error.' });
}
})
Fixed the hanging issue. It was indeed something wrong with the way I wrote passport.js as the code works more for MongoDB rather than MySQL.
Here is the new working passport.js:
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
connection.query("select * from users where id = "+id,function(err,rows){
done(err, rows[0]);
});
});
passport.use(new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows pass back of entire request to the callback
},
function(req, email, password, done) { // callback with email and password from form
// Match User
connection.query("SELECT * FROM `users` WHERE `email` = '" + email + "'",function(err,rows){
if (err)
return done(err);
// Check if Email exists in database
if (!rows.length) {
return done(null, false, { message: 'Email is not registered' });
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (!( rows[0].password == password))
return done(null, false, { message: 'Password is incorrect.' });
// All is well, return successful user
return done(null, rows[0]);
});
}));
};
I have made a simple Node app using authentication. I am able to signup using the form but I am not able to login using the login form.
I have written the code below. Using this I can register using the signup route, but I am not able to log in. Also, I am not getting any error, I am just redirected to failure redirect path.
Here is the code I have written
var express = require('express'),
app = express(),
bodyParser = require('body-parser'),
mongoose = require('mongoose'),
User = require("./views/models/user"),
passport = require('passport'),
flash = require('connect-flash'),
morgan = require('morgan'),
cookieParser = require('cookie-parser'),
session = require('express-session'),
expressValidator = require('express-validator'),
LocalStrategy = require('passport-local').Strategy;
mongoose.connect("mongodb://localhost/travelogue");
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
// required for passport
app.use(bodyParser.urlencoded({extended :true}));
app.use(bodyParser.json());
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(require('express-session')({
secret : "Adish",
resave : false,
saveUninitialized : false,
}));
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.use(express.static('public'));
app.set("view engine","ejs");
//routes
app.get("/Login",function(req,res){
res.render("login");
});
app.get("/Signup",function(req,res){
res.render("signup");
});
app.get("/",function(req,res){
res.render("index");
});
// we will use route middleware to verify this (the isLoggedIn
function)
/*app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user : req.user // get the user out of session and pass to
template
});
});*/
app.get("/logout",function(req,res){
req.logout();
res.redirect("/");
});
// Express Validator
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
// process the signup form
app.post('/Signup', function(req, res){
var firstname = req.body.firstname;
var lastname = req.body.lastname;
var username = req.body.username;
var email = req.body.email;
var password = req.body.password;
var gender = req.body.gender;
// Validation
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Email is not valid').isEmail();
req.checkBody('username', 'Username is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
var errors = req.validationErrors();
if(errors){
res.render('signup',{
errors:errors
});
} else {
var newUser = new User({
firstname: firstname,
lastname : lastname,
username : username,
email : email,
password : password,
gender : gender
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
req.flash('success_msg', 'You are registered and can now
login');
res.redirect('/login');
}
});
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
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);
});
}
));
app.post('/login', passport.authenticate('local', {
successRedirect : '/profile', // redirect to the secure profile
section
failureRedirect : '/login', // redirect back to the signup page
if there is an error
failureFlash : true // allow flash messages
}));
app.get('/profile',function(req,res){
res.render('profile.ejs');
});
app.listen(process.env.PORT,process.env.IP,function(){
console.log("Server is running !");
});
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
This is the userSchema used to register (user.js):
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
// User Schema
var UserSchema = mongoose.Schema({
firstname : String,
lastname : String,
username : {type :String, unique : true},
email : String,
password : String,
gender : String,
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
if(err)
console.log(err);
});
});
};
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
};
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
};
module.exports.comparePassword = function(candidatePassword, hash,
callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
};
The problem is when I want pass object to view. I got a message user is undefined. The object is defined after if statement is Match and in serializeUser function. I do not know why I lose this object in route to lobby.
Here I post the route code.
var express = require('express');
var router = express.Router();
var User = require('../models/user');
var Facebook = require('../models/facebook');
var passport = require('passport')
var LocalStrategy = require('passport-local').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;
router.get('/lobby', function(req, res){
console.log("User req "+req.user);// here I got the message user undefined and I do not know why
res.render('lobby',{ user:req.user});
// res.render('lobby');
});
router.get('/logout',function(req, res){
req.logout();
req.flash('success_msg', 'You have been logged out');
res.redirect('/');
});
function ensureAuthenticated(req, res, next){
if(req.isAuthenticated()){
return next();
}else{
res.redirect('/');
}
}
router.post('/login', passport.authenticate('local', {
successRedirect : '/users/lobby',
failureRedirect : '/',
failureFlash : true
}));
//Passport strategy
passport.serializeUser(function(user, done) {
console.log("serizlize "+user); //here I got object user and it is defined
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
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){
return done(null, false, {message: 'wrong data'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
}else{
return done(null, false,{message: 'wrong data'});
}
});
});
}));
module.exports = router;
enter link description here
*******Edit*****
Problem solved. I just red that you have to initalize express session before passport session. That works for me.
In your server file (my is app.js)
//express session
app.use(session({
secret: 'yoursecrethere',
saveUninitialized: true,
resave: false
}));
//Passport init
app.use(passport.initialize());
app.use(passport.session());
Heres console output when running and entering an incorrect password ..
info: Listening on 127.0.0.1:3000
debug: GET /
debug: Incorrect password
/home/bob/git/authenticate-nodejs-prototype/node_modules/mongodb/lib/utils.js:98
process.nextTick(function() { throw err; });
^
TypeError: req.flash is not a function
at allFailed (/home/bob/git/authenticate-nodejs-prototype/node_modules/passport/lib/middleware/authenticate.js:118:15)
Heres the actual code. Any ideas what might be causing this? ..
var express = require('express'),
app = express(),
http = require('http').Server(app),
winston = require('winston'),
passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
ipaddress = '127.0.0.1',
port = 3000,
MongoClient = require('mongodb').MongoClient,
ObjectId = require('mongodb').ObjectID,
assert = require('assert'),
mongoUrl = 'mongodb://' + ipaddress + ':27017/authenticate-nodejs-prototype',
flash = require('connect-flash');
// during dev
winston.level = 'debug';
/*
* Database query
* Searches db for user that matches provided username
*/
var findUser = function (db, id, callback) {
var cursor = db.collection('userInfo').find({username: id.username});
var result = [];
cursor.each(function (err, doc) {
assert.equal(err, null);
if (doc !== null) {
result.push(doc);
} else {
callback(result);
}
});
};
// configure passport to use username and password authentication
passport.use(new LocalStrategy(
function(username, password, done) {
MongoClient.connect(mongoUrl, function (err, db) {
assert.equal(null, err);
findUser(db, {username:username, password:password}, function (result) {
db.close();
if (err) {
return done(err);
}else if (result === []) {
winston.debug('Incorrect username');
return done(null, false, { message: 'Incorrect username.' });
}else if (password !== result.password) {
winston.debug('Incorrect password');
return done(null, false, { message: 'Incorrect password.' }); // this is the line that causes error
}
return done(null, result);
});
});
}
));
passport.serializeUser(function(user, done) {
return done(null, user);
});
passport.deserializeUser(function(id, done) {
MongoClient.connect(mongoUrl, function (err, db) {
assert.equal(null, err);
findUser(db, id, function (result) {
db.close();
return done(null, result);
});
});
});
app.configure(function() {
app.use(express.static('public'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(flash());
});
/*
* setup endpoints
*/
app.get('/', function(req, res){
winston.debug('GET /');
res.sendfile('views/index.html');
});
app.get('/success', function(req, res){
winston.debug('GET /success');
res.sendfile('views/success.html');
});
app.post('/login',
passport.authenticate('local', { successRedirect: '/success',
failureRedirect: '/',
failureFlash: true })
);
// start server
http.listen(port, ipaddress, function(){
winston.info('Listening on ' + ipaddress + ':' + port);
});
You need to add flash to express, so that it can be used as middleware.
var flash = require('connect-flash');
...
app.use(flash());
Edit: the reason for this is that flash isn't actually built into Passport or Express, it's a separate package provided by connect-flash. So you need to install it with npm and then include it as shown above.
I am currently working on a node js project with passport authentication.
But i get the following error message:
Error: "Unknown authentication strategy "
Here is my Code:
LocalStrategy = require('passport-local').Strategy;
var UserModel = require('../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){
return done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
passReqToCallback: true
}, function(req, username, password, done){
process.nextTick(function(){
User.findOne({username: username}, function(err, user) {
if(err){
return done(err);
}
if(user){
return done(null, false, req.flash('signUpErr', 'The mail is taken'));
} else {
var newUser = new UserModel();
newUser.name = username;
newUser.password = newUser.generateHash(password);
newUser.save(function(err){
if(err){
throw err;
}
console.log('All Ok');
return done(null, newUser);
})
}
});
});
}));
}
Route:
//Post requests
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect : '/signup'
}));
My model:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var UserSchema = new mongoose.Schema({
name: String,
password: String
});
UserSchema.method.generateHash = function(password){
return bcrypt.hash(password);
};
module.exports = mongoose.model('UserModel', UserSchema);
I would really need your help, thanks!
Check if you passing the strategy along with the user credentials
var credentials = {
username:"username",
password:"password",
strategy:"local"
};
$http.post('auth/signin', credentials);
Server side
function passportAuthenticate(req, res, next, strategy) {
passport.authenticate(strategy, function(err, user, info) {
if (err || !user) {
res.status(400).send(info);
} else {
next(req, res, user);
}
})(req, res, next);
}