done is not a function error in passport js - node.js

I'm using passportjs for the authentication and session. I get the ussername from mysql and the input field from client side but when the done is called on verification, I get done is not a function.
The server.js :
var express = require('express');
var app = express();
var path = require('path');
var bodyParser = require('body-parser');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var cookieParser = require('cookie-parser');
// app.use(app.router);
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.json());
app.use(express.static(__dirname+"/staticFolder"));
var mysql = require('mysql');
var connection = mysql.createConnection({
host:'127.0.0.1',
user:'root',
password:'sdf',
database:'abc'
});
connection.connect(function(err){
if(err){
throw err;
}
});
passport.serializeUser(function(user,done){
console.log("serializeUser" + user);
done(null,user.body.username);
})
passport.deserializeUser(function(id, done) {
done(null, user);
});
passport.use(new LocalStrategy({
passReqToCallback : true
},function(username, password, done) {
connection.query("select * from employeedetails where empid = "+username.body.username,function(err,user,w){
if(err)
{
console.log(err+"fml $$$$$$$$$$");
return done(err);
}
if(username.body.password == user[0].password){
console.log(user[0].empid+" login");
return done(null,user[0].empid);
}
else{
return done(null,false,{message: 'Incorrect password'});
console.log(user[0].empid+" fml");
}
});
}));
app.get('/',function(request,response){
response.sendFile(__dirname+"/staticFolder/view/");
})
app.post('/saveEmployeeDetails',function(request,response){
response.end();
})
app.get('/login',function(request,response){ //the file sent when /login is requested
response.sendFile(__dirname+"/staticFolder/view/login.html");
})
app.post('/loginCheck',passport.authenticate('local', {
successRedirect : '/',
failureRedirect : '/login',
failureFlash : true //
}),
function(req, res) {
console.log("hello");
res.send("valid");
res.redirect('/');
});

Can you please refer to the below link which talks about the same error
https://github.com/jaredhanson/passport/issues/421
It says when you remove the (passReqToCallBack: true) options the error does not occur

In your passport.js config file, passport.use(new LocalStrategy) callback
function depending on which strategy you are using you will need a certain number of arguments.I just had to add "req"
as the first argument in mine.
passport.use(new LocalStrategy({
passReqToCallback: true
},
function (req, apikey, done) {
//ADD REQ UP HERE
process.nextTick(function () {
findByApiKey(apikey, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Unknown apikey : ' + apikey
});
}
return done(null, user);
})
});
}));

It would be an issue of missing parameters in the function.
Here is an example source code for passport-openidconnect strategy:
// Using 'passport-openidconnect' strategy
var OpenidConnectStrategy = require('passport-openidconnect');
var strategy = new OpenidConnectStrategy(
{
issuer: process.env.OAUTH_ISSUER,
authorizationURL: process.env.OAUTH_AUTHORIZATION_URL,
tokenURL: process.env.OAUTH_TOKEN_URL,
userInfoURL: process.env.OAUTH_USERINFO_URL,
clientID: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
callbackURL: process.env.OAUTH_CALLBACK_URL,
},
// Parameters in the function should be appropriate with the strategy
function (issuer, sub, profile, accessToken, refreshToken, done) {
return done(null, profile);
}
);

Related

req.user undefined using Express & Node & Passport

I am currently creating a small user authentication app using Node + Express + Passport. When the user logs in, they are rerouted automatically to the index page "/" and a session should be established with passports authentication. For some reason when trying to console.log(req.user), it is returning "undefined".
The authentication with passport seems to be working properly with the post route
app.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
})
But the session is not being established with the user model. I'd like to eventually store the userId in the session. Here is a look at my current set up with user model and passport implementation on the server file.
const mongoose = require("mongoose");
const passportLocalMongoose = require('passport-local-mongoose');
const userSchema = mongoose.Schema({
username: String,
email: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
const user = mongoose.model("User", userSchema);
module.exports = user;
-----------------------------------------------------------------------------------------
const express = require("express"),
mongoose = require("mongoose"),
bodyParser = require("body-parser"),
session = require("express-session"),
User = require("./models/user"),
passport = require('passport'),
LocalStragety = require('passport-local'),
app = express();
mongoose.connect("mongodb://localhost/shopping_cart_app", { useNewUrlParser: true })
.then(console.log("MongoDB Connected"))
.catch(err => console.log(err));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/views'));
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStragety(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
})
I've tried looking into Passports config a bit more but on the documentation provided, it states that once passport.authenticate runs, a session with the user is established. Any tips would be greatly appreciate.
Thanks
I know this may seem simple, but have you tried req.body.user?
The req.body contains the data submitted by the user. The documentation suggest that you use a body parser to populate the information because it's undefined by default. However, instead of using the app object I use express router without parsing.
const express = require("express");
const router = express.Router();
router.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
console.log(req.body.user);
})
for more information: req.body
Try this one, In my project, it is working.
LocalStrategy
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var admins = mongoose.model('admins');
var bCrypt = require('bcrypt-nodejs');
var flash = require('connect-flash');
var moment = require('moment');
// User
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(obj, done) {
console.log("deserializing " + obj);
done(null, obj);
});
passport.use('adminlogin',new LocalStrategy(
function(username, password, done) {
admins.findOne({ 'email' : username },
function(err, user) {
//console.log(username);
if (err)
return done(err);
if (!user){
//console.log('Username '+username+' does not Exist. Pleasr try again.');
return done(null, false, { message: 'Incorrect Username/Password. Please try again.' });
}
if (!isValidPasswordAdmin(user, password)){
//console.log('Invalid Password');
return done(null, false, { message: 'Incorrect Password. Please try again.' });
}
return done(null, user);
}
);
})
);
var isValidPassword = function(user, app_pin){
return bCrypt.compareSync(app_pin, user.app_pin);
}
var isValidPasswordAdmin = function(user, password){
return bCrypt.compareSync(password, user.password);
}
module.exports = passport;
Login Route
router.post('/login', function (req, res, next) {
admins.find({}, function (err, user) {
if (err) {
console.log('internal database error');
req.flash('error', 'Database Error');
res.redirect('/admins');
} else {
passport.authenticate('adminlogin', function (err, user, info) {
if (err) {
console.log(err);
req.flash('error', 'Database Error');
res.redirect('/admins');
} else if (!user) {
req.flash('error', info.message);
res.redirect('/admins');
} else {
req.logIn(user, function (err) {
if (err) {
req.flash('error', 'Database Error');
res.redirect('/admins');
} else {
res.redirect('/admins/home');
}
});
}
})(req, res, next);
}
});
});

PassportJs Authentication Infinite Loop and Execute(default) query

I am trying to build the authentication system using PassportJs and Sequelize. I made the registration system by myself, using Sequelize. I want to use PassportJS only for Login.
It does not redirect me to the failureRedirect route, neither to the SuccessRedirect one, but when submitting the form it enters into an endless loop and in my console, the following message appears:
Executing (default): SELECT `id`, `username`, `lastName`, `password`, `email`, `phone`, `createdAt`, `updatedAt` FROM `user` AS `user` LIMIT 1;
My project is structured in: users_model.js , index.js and users.js (the controller).
The code I have in my index.js looks like this:
//===============Modules=============================
var express = require('express');
var bodyParser = require('body-parser');
var session = require('express-session');
var authentication= require('sequelize-authentication');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var passportlocal= require('passport-local');
var passportsession= require('passport-session');
var User = require('./models/users_model.js');
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);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
console.log(id);
});
});
var users= require('./controllers/users.js');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use('/users', users);
app.use('/events', events);
//-------------------------------------------Setup Session------------
app.use(session({
secret: "ceva",
resave:true,
saveUninitialized:true,
cookie:{},
duration: 45 * 60 * 1000,
activeDuration: 15 * 60 * 1000,
}));
// Passport init
app.use(passport.initialize());
app.use(passport.session());
//------------------------------------------------Routes----------
app.get('/', function (req, res) {
res.send('Welcome!');
});
//-------------------------------------Server-------------------
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
In my controller, I made the registration system by myself, using Sequelize. In users.js, I have:
var express = require('express');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var passportlocal= require('passport-local');
var passportsession= require('passport-session');
var router = express.Router();
var User = require('../models/users_model.js');
//____________________Initialize Sequelize____________________
const Sequelize = require("sequelize");
const sequelize = new Sequelize('millesime_admin', 'root', '', {
host: 'localhost',
dialect: 'mysql',
pool: {
max: 5,
min: 0,
idle: 10000
}
});
//________________________________________
router.get('/',function(req,res){
res.send('USERS');
});
router.get('/register', function(req, res) {
res.render('registration', {title: "Register" });
});
router.post('/register', function(req, res) {
var email = req.body.email;
var password = req.body.password;
var username= req.body.username;
var lastname= req.body.lastname;
var phone= req.body.phone;
User.findAll().then(user => {
usersNumber = user.length;
x=usersNumber+1;
var y =usersNumber.toString();
var uid='ORD'+ y;
User.sync().then(function (){
return User.create({
id:uid,
email: email,
password:password,
username: username,
lastName: lastname,
phone: phone,
});
}).then(c => {
console.log("User Created", c.toJSON());
res.redirect('/users');
}).catch(e => console.error(e));
});
});
router.get('/login',function(req,res){
res.render('authentication');
});
//router.post('/login', function(req, res, next) {
// console.log(req.url); // '/login'
// console.log(req.body);
// I got these:{ username: 'username', password: 'parola' }
// passport.authenticate('local', function(err, user, info) {
// console.log("authenticate");
// console.log('error:',err);
// console.log('user:',user);
// console.log('info:',info);
// })(req, res, next);
//});
router.post('/login', passport.authenticate('local', {
successRedirect: '/events',
failureRedirect: '/users/register'
}));
router.get('/logout', function(req, res){
req.logout();
res.redirect('/users/login');
});
//__________________________________________
module.exports = router;
Main problem: not an infinite loop, but incorrect usage of Sequelize
This is not an infinite loop but just a hanging response from the server which would be ended with a timeout error.
When you do this:
passport.use(new LocalStrategy(
function(username, password, done) {
...
}
));
...passport and express wait for the done function to be called. Once it's done(), they go forward in the middleware chain and send the response to the client.
The done function is not called, because Sequelize seems to not support callback functions, but promises. So, the correct way to call Sequelize methods is:
User.findOne({ username: username }).then(user => {
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
done(null, user);
}).catch(err => done(err));
(de)Serializing the session user
Seems that there is no id field in the user instances, but userid. Therefore we have to do:
passport.serializeUser(function(user, done) {
done(null, user.userid);
});
passport.deserializeUser(function(id, done) {
User.findOne({ userid: id }).then(user => {
done(null, user);
console.log(id);
}).catch(err => done(err));
});
For reference, this commit fixes these issues.

Passport: Unknown authentication strategy "local"

I'm new to NodeJS and I try to build a login/registration system. Registration works fine but I'm currently unable to login.
I find a example app using passport and nodejs, so based on this example I build the registration form and the login form.
http://blog.robertonodi.me/node-authentication-series-email-and-password/
When I try to login I get an 'Unknown authentication strategy "local" error'. Can anybody explain what I'm doing wrong?
My code
(edit: added some changes from answers/comments and filenames)
Express config (config/express.config.js)
app.use(session({
store: new MongoStore({
url: 'mongodb://' + config.url + ':' + config.port + '/' + config.name
}),
secret: 'secretkey',
key: 'skey.sid',
resave: false,
saveUninitialized: false,
cookie : {
maxAge: 604800000 //7 days in miliseconds
}
}));
app.use(passport.initialize());
app.use(passport.session());
require(path.join(__dirname, 'auth.config'))(passport); //Load passport config
app.use(function(req, res, next) {
req.resources = req.resources || {};
// res.locals.app = config.app;
res.locals.currentUser = req.user;
res.locals._t = function (value) { return value; };
res.locals._s = function (obj) { return JSON.stringify(obj); };
next();
})
Passport config (config/auth.config.js)
var path = require('path');
var passport=require('passport');
var User = require(path.join(__dirname, '..', 'models', 'user.model'));
module.exports = function(passport) {
passport.serializeUser(function(user, done){
done(null, false);
});
passport.deserializeUser(function(id, done){
console.log("deserializeUser called", id);
User.findById(id, function (err, user) {
done(err, user);
});
});
//load strategy files
require(path.join(__dirname, 'strategies', 'local-strategy'));
//TODO: Facebook
//TODO: Twitter
//TODO: Google
}
Local strategy (/config/strategies/local-strategy.js)
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = mongoose.model('User');
module.exports = function () {
console.log("LocalStrategy called");
passport.use(new LocalStrategy({
usernameField : 'username',
passwordField : 'password'
},
function(username, password, done) {
User.authenticate(username, password, function(err, user) {
if (err) {
return done(err);
}
if(!user) {
return done(null, false, {message: 'Invalid username or password'});
}
return done(null, user);
})
}))
}
Auth Controller (login only) (/controllers/auth.controller.js)
module.exports.loginUser = function(req,res, next) {
console.log("Auth.config", path.join(__dirname, 'strategies', 'local-strategy'))
passport.authenticate('local', function (err, user, info) {
if (err || !user) {
console.log("Error", info);
return res.status(400).send(info);
}
req.logIn(user, function(err) {
if (err) {
return next(err);
// return res.status(404).send("Username or password incorrect");
}
})
res.status(200).json(user);
})(req, res, next);
}
You forgot to import passport config file in your app.js.
import passport config after initializing passport.
app.use(passport.initialize());
app.use(passport.session());
// Add the line below, which you're missing:
require('./path/to/passport/config/file')(passport);
i have done like this and it worked
$npm install passport-local
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy; /* this should be after passport*/
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);
});
}
));
this fix the error. need to use 'local' when you create a new LocalStrategy
passport.use('local', new LocalStrategy({
usernameField:'useName',
passwordField: 'password',
passReqToCallback: true

Passport method isAuthenticated() is false even after successful authentication using Google Strategy

I'm new to MEAN stack and I'm trying to setup a simple social login using google passport strategy. I can successfully authenticate myself, but when calling a redirect on success, the middle ware function isLoggedIn keeps showing req.isAuthenticated() to be false. Below are code snippets. I saw that there were multiple posts on this issue but none of the answers seem to work for me. Kindly help me resolve this issue.
passport.js
var Auth = require('./auth.js');
var ubCust = require('../models/ubCust.js');
var FacebookStrategy = require('passport-facebook').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
//var FacebookStrategy = require('passport-facebook').Strategy;
module.exports= function(passport){
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
ubCust.findById(id,function(err,user){
done(err, user);
})
});
passport.use(new GoogleStrategy ({
clientID: Auth.googleAuth.clientID,
clientSecret: Auth.googleAuth.clientSecret,
callbackURL : Auth.googleAuth.callbackURL
},
function(token, refreshToken, profile, done) {
// Create or update user, call done() when complete...
process.nextTick(function(){
ubCust.findOne({'google.id' : profile.id}, function(err, user) {
if (err)
return done(err);
if(user)
return done(null,user);
else
{
var newUser = new ubCust;
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value;
newUser.save(function(err){
if (err)
throw err;
return done(null,newUser);
});
console.log(profile);
}
//done(null, profile, tokens);
}); //findOne
});//nextTick
}
));
};
route(authController.js)
module.exports = function(app,passport){
app.get('/api/getprofauth',isLoggedIn,function(req,res){
console.log('In getprofile authentication api');
//console.log('req.query :',req.query);
res.send(req.user);
});
app.get('/auth/google',
passport.authenticate('google',{scope: ['email','profile']})
);
app.get('/auth/google/callback',
passport.authenticate('google', {failureRedirect: '/'}),
function(req, res) {
console.log('auth success!! ',req.isAuthenticated(),req.user);
res.redirect('/api/getprofauth');
}
);
function isLoggedIn(req,res,next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
{
console.log('isAuthenticated Success');
return next();
}
else{
console.log('req.user',req.user,req.isAuthenticated());
console.log('isAuthenticated Failure');
res.redirect('/');
}
// if they aren't redirect them to the home page
}//isLoggedIn
}
app.js(server)
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var config = require('./config');
var passport = require('passport');
var cookieParser = require('cookie-parser');
app.use(cookieParser());
var session = require('express-session');
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
var authController = require('./controllers/authController.js');
var port = process.env.PORT||3000;
app.use(express.static(__dirname+ '/public'));
app.set('view engine','ejs');
app.get('/',function(req,res){
//redirecting request to home page '/' to index page
res.redirect('/index.htm');
});
mongoose.connect(config.getDBConnectionString());
app.use(passport.initialize());
app.use(passport.session());
var pp = require('./config/passport');
pp(passport);
apiController(app);
apibike(app);
appoController(app);
authController(app,passport);
app.listen(port);

passport js local authentication using sequelize

I am trying to use passport local auth with sequelize . When I submit login form, the request/respond cycle never end and there is no error message in the terminal .
Here are all of my codes:
app.js
var Sequelize = require('sequelize'),
express = require('express'),
bodyParser = require('body-parser'),
cookieParser = require('cookie-parser'),
passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
User = require('./models/users');
........ and other imports.....
//route import , model injection
var auth = require('./routes/auth')(User);
.......................
app.use(session({
store: new RedisStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
console.log(user);
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id).then(function(user){
done(null, user);
}).catch(function(e){
done(e, false);
});
});
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({where: {username: username}}).then(function(err, user) {
if (err) { return done(err); }
if (!user) {
console.log('Incorrect username.');
return done(null, false, { message: 'Incorrect username.' });
} else if (password != user.password) {
console.log('Incorrect password');
return done(null, false, { message: 'Incorrect password.' });
} else {
console.log('ok');
done(null, user);
}
});
}
));
and routes/auth.js :
var express = require('express'),
passport = require('passport');
var routes = function(User) {
var router = express.Router();
// routes for registration
router.route('/register')
.get(function(req, res) {
res.render('register');
})
.post(function(req, res) {
User.count().then(function(number) {
if (number >= 1) {
res.redirect('/auth/login');
} else {
User.create({
username: req.body.username,
password: req.body.password
});
res.redirect('/auth/login');
}
});
});
//routes for login
router.route('/login')
.get(function(req, res) {
res.render('login');
})
.post(function(req, res) {
passport.authenticate('local', { successRedirect: '/dashboard',
failureRedirect: '/auth/login' });
});
return router;
};
module.exports = routes;
Why does the request/response cycle never end?
Your current middleware definition for './login' POST is incorrect and does not send a response, which is why it doesn't end (until it times out).
Instead of calling passport.authenticate in a middleware function, the result of calling passport.authenticate should be used as middleware itself. I suggest the following:
router.route('/login')
.get(function(req, res) {
res.render('login');
})
.post(passport.authenticate('local', { successRedirect: '/dashboard',
failureRedirect: '/auth/login' });
);
See http://passportjs.org/docs/authenticate for an example.
Race condition in registration code
You didn't ask about this, but there is a race condition in your middleware for './register' POST.
User.create returns a promise for saving the created user. Until that promise is resolved there is no guarantee that the user exists in the backing datastore. However, immediately after calling create, your code redirects to the login endpoint which would query the database for that user.
Here is some code that avoids this problem:
User.create({ ... })
.then(function() {
res.redirect('/auth/login');
})
.catch(function(err) {
// Handle rejected promise here
})
The catch is included because it is always good practice to handle rejected promises and thrown exceptions.

Resources