bookshelf.js doesnt work with passport - node.js

I hava a simple auth panel with bookshelf and passport, but when i try log in i get white empty page 500. I try all solutions which i found in web. Please help.
config/passport.js
...
passport.use('local-login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
User.where({username: username}).fetch().then(function(err, user) {
if (err) return done(err);
if (!user) {
return done(null, false, req.flash('loginMessage', 'Cant find user!'));
}
user = user.toJSON();
if(User.validPassword(password, user.password)){
return done(null, false, req.flash('loginMessage', 'Invalid pass!'));
}
return done(null, user);
}).catch(function(err) {
console.error(err);
});
}
));
...
routes/auth.js
...
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/users/profile',
failureRedirect: '/auth/login',
failureFlash: true
}));
...
server.js
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const flash = require('connect-flash');
const path = require('path');
const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const config = require('./config/app.js');
const index = require('./routes/index');
const auth = require('./routes/auth');
const users = require('./routes/users');
require('./config/passport.js')(passport);
const app = express();
app.set('env', config.website.env);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')))
app.use(session({
secret: config.security.salt,
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use('/', index);
app.use('/auth', auth);
...

I think the major issue here is in the use of then(). It does not take an err argument as traditional callbacks.
Another minor issue is that the catch() should forward the error to passport instead of just logging it.
So try changing it to something like
passport.use('local-login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
new User({username: username})
.fetch()
.then(function(user) {
if (!user) {
return done(null, false,
req.flash('loginMessage', 'Cant find user!'));
}
user = user.toJSON();
if (User.validPassword(password, user.password)) {
return done(null, false,
req.flash('loginMessage', 'Invalid pass!'));
}
return done(null, user);
})
.catch(function(err) {
return done(err);
});
}
));
As a side note I was a bit confused by User.validPassword(). Does it return a true value for invalid passwords?

Related

Passportjs req.isAuthenticated always shows false

i am worked nodejs/Angular passport middleware login Authentication working fine but when I try to get login username with the help of req.authentication's not call the passport.deserializeUser function always req.authentication is shown false help how to rectify this problem any ideas.
here i pasted my tried code
Server.js
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
// const logger = require('morgan');
var cookieParser = require('cookie-parser');
const chalk = require('chalk');
const errorHandler = require('errorhandler');
const dotenv = require('dotenv');
const path = require('path');
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo')(session);
const passport = require('passport');
const expressValidator = require('express-validator');
const http = require('http');
const app = express();
// cros origin handling method start
const cors = require('cors');
dotenv.load({ path: '.env.Config' });
app.use(bodyParser.json());
app.use(express.static(__dirname + "/public"));
app.set('views', __dirname + '\\public');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
//mongodb config
mongoose.connect(process.env.MONGODB_URI);
mongoose.connection.on('error', () => {
console.log('%s MongoDB connection error. Please make sure MongoDB is running.', chalk.red('✗'));
process.exit();
});
app.use(cookieParser(process.env.SESSION_SECRET));
app.enable('trust proxy'); // add this line
//express session config
app.use(session({
name: 'UpgradeApp.sid',
resave: true,
// saveUninitialized: true,
secret: process.env.SESSION_SECRET,
store: new MongoStore({
url: process.env.MONGODB_URI,
autoReconnect: true
}),
proxy: true, // add this line
saveUninitialized: false,
cookie: {//New
maxAge: 36000000,
httpOnly: false,
secure: false
}
}));
require('./src/SchemaConfig/PassportConfig');
//cors origin config
app.use(cors({
origin: ['http://localhost:4200', 'http://127.0.0.1:4200', 'http://192.168.1.93:4200'],
credentials: true
}));
//bodyparser config
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: "200mb" }));
app.use(bodyParser.urlencoded({ limit: "200mb", extended: true, parameterLimit: 200000 }));
app.use(passport.initialize());
app.use(passport.session());
//schema config
const UserConfig = require('./src/SchemaConfig/UserSchema');
function isAuthenticated(req, res, next) {
var ss = req.isAuthenticated();//always show false
if (req.isAuthenticated()) next();
else return res.json('Un-Authenticated');
};
app.get('/logout', isAuthenticated, function (req, res) {
req.logout();
res.json("logout");
});
app.get('/GetUser', isAuthenticated, function (req, res, next) {
return res.json(req.user.UserName);
});
app.post('/login', UserConfig.loginVerify);
app.set('port', process.env.App_PORT || 3000);
app.listen(app.get('port'), () => {
console.log('%s server running on port', chalk.green('✓'), app.get('port'));
console.log(' Press CTRL-C to stop\n');
});
PassportConfig
const User = require('../SchemaConfig/UserSchema');
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt-nodejs');
passport.use('local', new LocalStrategy({
usernameField: 'Email',
passwordField: 'Password'
},
function (Email, Password, done) {
debugger
User.findOne({ Email: Email }, function (err, user) {
debugger
if (err) { return done(err); }
if (!user) {
return done(null, false, {
ErrorMsg: 'Incorrect Email.'
});
}
if (user) {
GlobalUserPwd = user.Password;
}
if (!ComparePassword(Password)) {
return done(null, false, {
ErrorMsg: '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);
});
});
function ComparePassword(CandidatePassword) {
return bcrypt.compareSync(CandidatePassword, GlobalUserPwd)
};
Userschema
exports.loginVerify = (req, res, next) => {
passport.authenticate('local', function (err, user, info) {
debugger
if (err) { return next(err); }
if (!user) { return res.status(501).json(info); }
req.logIn(user, function (err) {
if (err) { return next(err); }
return res.status(200).json({message:'Login Success'});
});
})(req, res, next);
};
Finally i found a solution for my problem passing login header request with withCredentials:true
const httpOptions = {
observe:'body',
withCredentials:true,
headers:new HttpHeaders().append('Content-Type','application/json')
};

NodeJS express session expire after page refresh

The session of my nodejs app is expiring every time I refresh the page, after login. It does work fine if I visit different pages but as soon as I refresh the page, the session ends. I've tried a couple of things but none of it seems to work. How can I keep it from expiring even after the page refresh? If I can store session in the database or someplace else to keep it from expiring.
Here are the files
Passport-init.js
var mongoose = require('mongoose');
var User = mongoose.model('user');
var localStrategy = require('passport-local').Strategy;
var bcrypt = require('bcrypt-nodejs');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
console.log('serializing user:',user.username);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
if(err) {
done(500,err);
}
console.log('deserializing user:',user.username);
done(err, user);
});
});
passport.use('login', new localStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
User.findOne({'username': username},
function(err, user) {
if(err) {
return done(err);
}
if(!user) {
console.log("UserName or Password Incorrect");
return done(null, false);
}
if(!isValidPassword(user, password)) {
console.log("UserName or Password is Incorrect");
return done(null, false);
}
return done(null, user);
});
}));
passport.use('signup', new localStrategy({
passReqToCallback : true
}, function(req, username, password, done) {
User.findOne({'username': username},
function(err, user) {
if(err) {
console.log("Error in signup");
return done(err);
}
if(user) {
console.log("Username already exist" + username);
return(null, false);
}
else {
var newUser = new User();
newUser.username = username;
newUser.password = createHash(password);
newUser.save(function(err) {
if(err) {
console.log("Error in saving user");
throw err;
}
console.log(newUser.username + ' Registration succesful');
return done(null, newUser);
});
}
});
}));
var isValidPassword = function(user, password) {
return bcrypt.compareSync(password, user.password);
}
var createHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(10), null);
}
};
Auth.js
var express = require('express');
var router = express.Router();
module.exports = function(passport) {
router.get('/success', function(req, res) {
res.send({state: 'success', user: req.user ? req.user : null});
});
router.get('/failure', function(req, res) {
res.send({state: 'failure', user: null, message: 'Invalid Username or Password'});
});
router.post('/login', passport.authenticate('login', {
successRedirect: '/auth/success',
failureRedirect: '/auth/failure'
}));
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/auth/success',
failureRedirect: '/auth/failure'
}));
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
return router;
};
Server.js
var express = require('express');
var path = require('path');
var app = express();
var server = require('http').Server(app);
var logger = require('morgan');
var passport = require('passport');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var mongoose = require('mongoose');
var MongoStore = require('connect-mongo')(session);
mongoose.connect("mongodb://localhost:27017/scriptknackData");
require('./models/model');
var api = require('./routes/api');
var auth = require('./routes/auth')(passport);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use(session({
secret: 'super secret key',
resave: true,
cookie: { maxAge: 60000 },
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
var initpassport = require('./passport-init');
initpassport(passport);
app.use('/api', api);
app.use('/auth', auth);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
var port = process.env.PORT || 3000;
server.listen(port, function() {
console.log("connected");
});
As per express-session documentation
cookie.maxAge
Specifies the number (in milliseconds) to use when calculating the Expires Set-Cookie attribute. This is done by taking the current server time and adding maxAge milliseconds to the value to calculate an Expires datetime. By default, no maximum age is set.
And use express.session() before passport.session() to ensure login session is stored in correct order. passport docs
In your case you have specified maxAge as 60000ms (60sec) only. Try this:
...
app.use(session({
secret: 'super secret key',
resave: true,
cookie: { maxAge: 8*60*60*1000 }, // 8 hours
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(passport.initialize());
app.use(passport.session());
...
Increase your cookie maxAge value according to your need, it will solve your issue.
I was facing the same issue as you and I got the problem fixed by doing this:
If anyone is having issues, this could probably help to solve it.
app.use(session({
secret: "our-passport-local-strategy-app",
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 24 * 60 * 60 * 1000
},
store: new MongoStore({
mongooseConnection: mongoose.connection,
ttl: 24 * 60 * 60 // Keeps session open for 1 day
})
}));
I had this problem and I found out how to fix it. In my case, this problem was just during using localhost during running react app on own port. I use the build production version, there was no problem. But it is not good to run build every time you need to see changes.
First I run Nodejs on 5000 port at localhost.
In React's package.json, I added "proxy": "http://localhost:5000/". After that, I ran react app on port 3000. Now when I use fetch, the URL to my API is not http://localhost:5000/api/login but just /api/login.
You can read more about that here:
https://create-react-app.dev/docs/proxying-api-requests-in-development/
Do not forget to remove the proxy from package.json when you will deploy to the server. This is good only for the development version.
As per the fine manual (emphasis mine):
Note that enabling session support is entirely optional, though it is recommended for most applications. If enabled, be sure to use express.session() before passport.session() to ensure that the login session is restored in the correct order.
In your case, the order is not correct. Try this:
...
app.use(session({
secret: 'super secret key',
resave: true,
cookie: { maxAge: 60000 },
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(passport.initialize());
app.use(passport.session());
...

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;

PassportJS: User Is Not Defined

Yes, I see that this question has been asked here and here, but the answers point to either making changes to your deserializeUser callback, or changing something in your Mongoose model.
I've tried the first to no avail and am using the regular ol' NodeJS driver, so I'm not quite sure where to pinpoint the root cause of my issue.
Here's my script:
AUTHENTICATE.JS:
var app = require('express');
var router = app.Router();
var assert = require('assert');
var bcrypt = require('bcrypt');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
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(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);
});
}
));
router.post('/login',
passport.authenticate('local', {successRedirect:'/',
failureRedirect:'/login',failureFlash: false}),
function(req, res) {
res.redirect('/');
});
For my app.js file I've tried a number of the fixes suggested in similar questions but nothing has made a difference. This is what it looks like:
APP.JS:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var expressValidator = require('express-validator');
var passport = require('passport');
var localStrategy = require('passport-local').Strategy;
var mongo = require('mongodb').MongoClient;
var session = require('express-session');
var bcrypt = require('bcrypt');
// Express Session
app.use(session({
secret: 'keyboard cat',
saveUninitialized: true,
resave: true,
cookie: {secure: true}
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//initialize passport for app
app.use(passport.initialize());
app.use(passport.session());
// make mongodb available to the application
app.use((req, res, next) => {
mongo.connect('mongodb://localhost:27017/formulas', (e, db) => {
if (e) return next(e);
req.db = db;
next();
});
});
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public'));
// 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
};
}
}));
//define routes here
app.set('port', (process.env.PORT || 3000));
app.listen(app.get('port'), function(){
console.log("The server is now listening on port "+app.get('port'));
});
module.exports = app;
Any help would be greatly appreciated, thank you.
As both questions you included point out, you need to define the User class first before you can use it. It's not something that passportjs or expressjs provide, you need to implement it for yourself or use another module that gives you that functionality (like mongoose).
In the first SO link you shared the answer suggested the OP implement a user model (User) in mongoose (it seems to be a popular choice).
The second links answer simplified things a bit by adding a hard-coded object to represent the user in the deserializer function.

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);

Resources