I'm very new to Passport & Node, I've been trying to solve an issue for several days without being able to find a solution that already exists on SO or the internet. I'm getting no errors or anything on login attempt, nothing in chrome dev, nothing in gitbash. Only problem is page never redirects, never seems to get through the passport.authenticate function inside my auth controller (/dologin). When I attempt a login, the browser never stops loading (ex. the circle keeps spinning for chrome), I have no problems with internet or anything of that nature, I only have this problem when implementing the login feature. One thing that I suspect might be an issue is that I do not have my localstrategy/serialization/deserialization in the right spot but I have tried it in app.js as well so at this point I'm really just too confused.
app.js - I tried including the initialize > session > localstrategy > serialize > deserialize in here, but it also didn't work so I just left initialize and session
// // Init passport authentication
app.use(passport.initialize());
// persistent login sessions
app.use(passport.session());
index.js
// route for login action
router.post('/dologin', auth.doLogin);
authController.js
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: 'Unknown User' });
}
User.comparePassword(password, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.getUserById(id, function (err, user) {
done(err, user);
});
});
userController.doLogin = function(req, res) {
passport.authenticate('local', { successRedirect: '/', failureRedirect: '/doLogin', failureFlash: true }),
function (req, res) {
res.redirect('/');
}
};
users.js (model) - includes getUserByUsername, comparePassword, getUserbyId
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if (err) throw err;
callback(null, isMatch);
});
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
Related
I have a little problem, and I have already spent one day trying to solve it with no results. I used passport.js, and the login and session work well, if I access address without login then I will be kicked to login page. But I have a little problem, when I fill datasource of datatable (cart.html) with routing from index.js, req.session.user will be undefined. But I checked in cart.html in routing of index.js, it has a value. I would appreciate anyone who can help me, thanks in advance.
Here is my routing cart.html of index.js
app.get('/cart',(req,res)=>{
//res.render('cart');
if (req.session.user) {
var userdata=req.session.passport.user;
res.render('cart',{username: userdata[0].USER,level:userdata[0].IDLEVEL});
}else {
res.redirect('/login');
}
});
here my passport :
passport.use(new LocalStrategy({passReqToCallback: true},
function(req,username, password, done) {
db.getConnection(function (err, connection) {
SQL="SELECT * FROM muser WHERE USER = ? and PASSWORD = ?";
connection.query(SQL, [username, password], function (err, rows) {
connection.release();
if(err) return done(err);
// if user not found
if (rows.length <= 0) {
return done('Cannot login');
//console.log(username+' '+password);
}
req.session.user=rows;
return done(null, rows);
});
});
}
));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(id, done) {
db.getConnection(function (err, connection) {
connection.query('SELECT * FROM muser WHERE ID = ?', [id], function(err, user) {
connection.release();
if(err) return done(err);
done(null, user);
});
});
});
function isAuthenticated(req, res, next) {
if (req.isAuthenticated()) return next();
res.redirect('/login');
}
app.get('/', isAuthenticated, function(req, res) {
res.render('home');
});
app.use(passport.initialize());
app.use(passport.session());
app.post('/login',
passport.authenticate('local', {
failureRedirect: '/login' }),
function(req, res) {
if (req.isAuthenticated()) {
res.redirect('/home');
}else {
res.redirect('/');
}
}
);
here my cart.html's codes
$("#dgcart").DataGrid({
dataSource: "http://192.168.10.120:5556/getcart" (routing below to get data of cart)
...});
here my bug cannot access req.session.user will be undefined
app.get('/getcart',(req,res)=>{
if (req.session.user) {
var userdata=req.session.passport.user;
SQL="SELECT TC.ID,TC.IDITEM,TC.KODEBARANG,TC.NAMA,SUM(TC.QTY) AS QTY,TC.PRICE, TC.SUBTOTAL"+'\n'+
"FROM cart TC "+'\n'+
"WHERE TC.IDUSER="+userdata[0].ID+'\n'+
"GROUP BY TC.KODEBARANG,TC.IDITEM,TC.KODEBARANG,TC.NAMA,TC.PRICE,TC.SUBTOTAL,TC.IDUSER";
rowsalasql=alasql(SQL);
console.log(SQL+' '+rowsalasql);
res.send(JSON.stringify(rowsalasql));
}else {
... will be here because undefined
}
});
I am trying to authenticate user ,when i try to login user after successful verification using req.logIn but it doesn't worked
router.post('/login', function(req, res, next) {
passport.authenticate('login',function (cb,data) {
//user verfication success
if(data){
req.logIn({user:"shamon"},function(err,result){
console.log("result",result,err)
res.send('login success');
});
}
})(req,res,next);
});
this console.log("result",result,err) gives me undefined,undefined
when i log req.user after logged i got undefined error
UPDATE
var LocalStrategy = require('passport-local').Strategy
module.exports = function(passport){
passport.use('local',new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},function (username,password,done) {
console.log('inside passport');
return done(null,true);
}));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null,user);
});
}
Just grab my implementation of password local-strategy. This is working for sure, but you will need to slightly modify it:
The strategy:
// Serialize
passport.serializeUser(function (user, done) {
done(null, user.id);
});
// Deserialize
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginError', 'No such user found.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if (!user.validPassword(password))
return done(null, false, req.flash('loginError', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashd
// all is well, return successful user
return done(null, user);
});
}
));
And the route:
router.post('/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.send({alert: req.flash('loginError')});
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
return res.send({redirect: '/'});
});
})(req, res, next);
});
Started learning Node today and I am almost positive my user is not being logged out correctly and I do not understand why. To login the user I've written the following code in my routes file
app.post('/api/signup', passport.authenticate('local-signup', function(err, res, req) {
console.log(res);
}));
then in another file this code to handle the logic of logging in my user
passport.serializeUser(function(user, done) {
console.log("serializeUser");
console.log(user);
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log("deserializeUser");
console.log(id);
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy(
{
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true
},
function(req, username, password, done) {
console.log(req.sessionID);
process.nextTick(function() {
User.findOne({ 'local.username': username }, function(err, user) {
if (err) {
return done(err);
}
if (user) {
return done(null, false, req.flash('signupMessage', "Username already taken"));
} else {
let newUser = new User();
newUser.local.username = username;
newUser.local.password = newUser.generateHash(password);
newUser.save( function(saveErr) {
if (saveErr) {
throw saveErr;
}
return done(null, newUser);
});
}
});
});
})
);
Then to logout my user I wrote the following code in my routes file
app.get('/api/session', function(req, res) {
console.log(req.sessionID);
req.logOut();
console.log(req.sessionID);
});
A few things confuse me about this code.
To my understanding serializeUser is suppose to change the user.id to bits and store it in the cookies but the console.log never prints which leads me to think that this code never runs, why? I read that req.login() is implicitly called so I should not need to worry about it.
The console.log which is inside the callback of LocalStrategy prints a sessionID. When is this set if I haven't created my new user yet or the console.log mentioned in point 1 never runs?
Inside of logout I call req.logOut() with a console.log(req.sessionID) before and after req.logOut() and these both print the same thing. I'm assuming these sessionID's are what the cookies use to determine a session is valid, if so, does this mean the user never logs out as the sessionID is never changed?
Thanks
I've got a node app that operates in isolation. Without js on in the client it just operates synchronously, setting cookies with passport.js. When the client is js enabled then the auth is done via a rest route.
All seems fine, except that if I have authenticated (and have cookies set) asynchronously, but then refresh the page (or navigate synchronously to a new one [for whatever reason]), the server sends the response with new cookies that overwrite the old ones and setting the user back to being unauthenticated.
// =============================================================================
// AUTHENTICATE (FIRST LOGIN) ==================================================
// =============================================================================
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile', // redirect to the secure profile section
failureRedirect: '/browse?p=0', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
}));
app.post('/async/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info, status) {
if (err) {
return res.send(err);
}
if (user) {
user.local = null;
return res.send(user);
} else {
return res.send(info);
}
})(req, res, next);
});
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// 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);
});
});
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
// asynchronous
process.nextTick(function() {
User.findOne({
'local.email': email
}).populate({
path: 'spots comments currentLocation'
}).exec(function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
// all is well, return user
else
User.populate(user, {
path: 'spots.bird',
model: 'Bird'
}, function(err, user) {
if (err)
return done(err);
else
User.populate(user, {
path: 'spots.location',
model: 'Location'
}, function(err, user) {
if (err)
return done(err);
else
console.log(util.inspect(user, showHidden = false, depth = 5, colorize = true));
return done(null, user);
});
});
});
});
}));
Node App:
app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
sessionVars = {
keys: ['<removed>'],
//secureProxy: true, // if you do SSL outside of node
maxAge: 2592000000
};
app.use(session(sessionVars));
app.use(flash());
require('./../modules/auth/passport')(passport);
app.use(passport.initialize());
app.use(passport.session());
Does anyone know why?
UPDATE: The async route doesn't seem to call the serializeUser function (which explains everything!). Does anyone know how to force serialization?
If I try a direct call: passport.serializeUser(user, done) then I need the done parameter, which isn't available in the routes file (although I could pass it through);
Does anybody know if serializeUser is meant to be called as a matter of course with passport strategies?
So I found that if you use the custom form of the authenticate function:
app.get('/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); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
it doesn't seem to pass it through the serializeUser function that you provide. The cookies for sessions stay in your browser and change all the time, even when you're logged out as they probably still 'tracking' your behaviour.
If you use the 'black box' version of the function:
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
that works because it calls serializeUser automatically.
I am using passport for authentication and session handling. Everything works fine so far. I implemented a "Sign in" form to add new users to the app. After a user is added I would like to log him/her in automatically.
What is the best way to achieve this - should I redirect to "/login" with the user credentials or is there another/better way(call serializeUser) to do that?
So far I think I did not really understand the way the "done" function (in serializeUser and LocalStrategy) is working or what it is doing ...
Here is my code:
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
authProvider.findUserById('users', id, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy( function(email, password, done) {
authProvider.getUserByEmail('users', email, function(error, user){
if(error) { return done(error); }
if (!user) { return done(null, false, { message: 'Unknown user ' + email });}
if (user.password != password) { return done(null, false);}
return done(null, user);
});
}
));
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login'}),
function(req, res) { res.redirect('/');});
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
if(error){
res.redirect('/sign');
} else {
res.redirect('/');
}
});
});
Does someone know how to do this?
Based on the Passport Guide req.login() is intended for this exact purpose.
This function is primarily used when users sign up, during which req.login() can be invoked to automatically log in the newly registered user.
Modifying krasu's code:
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
if ( error ){
res.redirect('/sign');
} else {
req.login(user, function (err) {
if ( ! err ){
res.redirect('/account');
} else {
//handle error
}
})
}
});
});
The potential error from the login() callback would come from your serializeUser() function.
Please use code from the #Weston answer bellow, because it's more universal and straightforward
Should look something like this
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
if(error){
res.redirect('/sign');
} else {
passport.authenticate('local')(req, res, function () {
res.redirect('/account');
})
}
});
});
I don't sure about name of strategy, but by default LocalStrategy should provide 'local' name
http://passportjs.org/guide/authenticate/
Try with:
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
passport.authenticate('local', (err, user) => {
req.logIn(user, (errLogIn) => {
if (errLogIn) {
return next(errLogIn);
}
return res.redirect('/account');
});
})(req, res, next);
});
});