I have a pretty simple application that is just an auth service and a profile page with a logout button at this point. I am trying to signup a user, who is redirected to /profile and then I logout. All of this works fine. I also have a verification email in there too but that is currently besides the point.
My issue is that when I go to log into the site it gives me no error messages, nothing, just redirects me to /login which is what my passport strategy's meant to do if there is an error.
Can anyone spot an error in my code that would cause me not to log into the site? I have included what I think are the important parts of my application.
app.js
// PASSPORT CONFIGURATION
require('./controllers/passport')(passport);
app.use(passport.initialize());
app.use(passport.session());
require('./routes/index.js')(app, passport);
passport.js login strategy
passport.use('login', new LocalStrategy({
usernameField: 'email',
passReqToCallback : true
},
function(req, email, password, done) {
User.findOne({ 'email' : email },
function(err, user) {
if (err) return done(err);
if (!user){
return done(null, false, req.flash('error', 'User not found'));
}
user.comparePassword(password, function(err, isMatch) {
if(err){
console.log(err);
}
if (isMatch) {
// Make sure the user has been verified
if (!user.isVerified) return done (null, false, req.flash('error', 'Your account has not been verified.' ));
var time = 14 * 24 * 3600000;
req.session.cookie.maxAge = time; //2 weeks
req.session.cookie.expires = new Date(Date.now() + time);
req.session.touch();
return done(null, user, req.flash('success', 'Successfully logged in.'));
} else {
return done(null, false, req.flash('error', 'Invalid Password'));
}
});
}
);
})
);
login route
app.post('/login', passport.authenticate('login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
user.js model
var UserSchema = new mongoose.Schema({
email: String,
password: String,
role: String,
avatar: String,
isVerified: { type: Boolean, default: false },
resetPasswordToken: String,
resetPasswordExpires: Date
});
UserSchema.plugin(passportLocalMongoose, { usernameField : 'email' });
UserSchema.plugin(timestamps);
UserSchema.pre('save', function(next) {
var user = this;
if (!user.isModified('password')) return next();
bcrypt.genSalt(10, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
I am not sure how this solved it but it did... I added in my auth middleware that checks if a user should be able to access the page or not and now I can log in. Here is my middleware that checks it.
middleware
exports.isUnauthenticated = function(req, res, next) {
if (!req.isAuthenticated()){
return next();
}
res.redirect('/');
};
Then I just required it and updated my post route to be
post login route
app.post('/login', isUnauthenticated, passport.authenticate('login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
Related
I have made a user register and login but I couldnt understand why req.user shows undefined.
I couldnt understand why it shows undefined.
I have middleware of :
app.use(passport.initialize());
app.use(passport.session());
And also I have middleware of body-parser
This is my register(post):
app.post('/register',[
// username must be an email
check('kullanici_adi').notEmpty(),
// email must be at least 5 chars long
check('email').isEmail(),
// email must be at least 5 chars long
check('sifre').notEmpty(),
], async (req, res) => {
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.sifre, salt);
let kullanici = new Kullanici({
kullanici_adi: req.body.kullanici_adi,
email: req.body.email,
sifre: hashedPassword,
});
const errors = validationResult(req);
if (!errors.isEmpty()) {
req.flash('danger', 'Bütün Alanların Doldurulması Zorunludur');
res.render('kayit', {
});
}
kullanici.save(function(err) {
if (err) {
console.log(err);
} else {
res.redirect('/');
}
});
});
This is my login parts:
app.get('/login', function(req, res){
res.render('login');
});
app.post('/login', (req, res, next) => {
passport.authenticate('local', {
failureRedirect: '/login',
successRedirect: '/',
failureFlash: true,
}) (req, res, next);
});
app.get('/logout', function(req, res){
req.logout();
req.flash('success', 'You are logged out');
res.redirect('/login');
});
And this is passportjs configure part:
passport.use(new LocalStrategy({
usernameField: 'kullanici_adi',
passwordField: 'sifre'
},
function(username, password, done) {
Kullanici.findOne({ kullanici_adi: username }, function (err, kullanici) {
if (err) { return done(err); }
if (!kullanici) {
return done(null, false, { message: 'Incorrect username.' });
}
bcrypt.compare(password, kullanici.sifre, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, kullanici);
} else {
return done(null, false, {message: 'Wrong password'});
}
});
});
}
));
passport.serializeUser(function(kullanici, done) { done(null, kullanici.id); });
passport.deserializeUser(function(id, done) { Kullanici.findById(id, function(err, kullanici) { done(err, kullanici); }); });
When I console.log(req.kullanici) in my index or post routes then it says undefined. But at the same time this undefined user can pass through ensureAuthenticated parts of my website.
Note: Some words meaning in English:
Kullanici = User,
kullanici = user,
kullanici_adi = username,
sifre = password,
email = email,
Can someone help met? Why it is being happened and how to solve this issue?
Full code:https://github.com/michelson/dante2/issues/229
So I am trying to add local authentication to my MEAN stack app.
Everything was running smoothly. Sign up works great. But I cannot log in as a user.
I am getting:
POST /login 302 3.979 ms - 58
on the console (via Morgan)
But there is certainly an error (express routes to the "failureRedirect" set via passport)
Could it be a problem reading from the db? Why would I be able to write to it then...
A test with chai reveals that the program cannot "find user by email" from the db via User Model
anyone have any clue why this is happening?
Here is my passport strategy code:
/config/passport.js
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/users');
module.exports = function(passport) {
// passport session setup ==================================================
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// local login =============================================================
passport.use('local-login', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
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.'));
return done(null, user);
});
}));
// local sign up =============================================================
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
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); // use the generateHash function in our user model
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
}));
};
Here's the routes:
// /login ======================================================================
app.route('/login')
.get(function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('login.html');
})
.post(passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/'
}));
// /signup ======================================================================
app.route('/signup')
.get(function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('signup.html');
})
.post(passport.authenticate('local-signup', {
successRedirect : '/profile',
failureRedirect : '/'
}));
Login Strategy
// passport/login.js
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
// check in mongo if a user with username exists or not
User.findOne({ 'username' : username },
function(err, user) {
// In case of any error, return using the done method
if (err)
return done(err);
// Username does not exist, log error & redirect back
if (!user){
console.log('User Not Found with username '+username);
return done(null, false,
req.flash('message', 'User Not found.'));
}
// User exists but wrong password, log the error
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null, false,
req.flash('message', 'Invalid Password'));
}
// User and password both match, return user from
// done method which will be treated like success
return done(null, user);
}
);
}));
We now define our routes for the application in the following module which takes the instance of Passport created in app.js above. Save this module in
module.exports = function(passport){
/* GET login page. */
router.get('/', function(req, res) {
// Display the Login page with any flash message, if any
res.render('index', { message: req.flash('message') });
});
/* Handle Login POST */
router.post('/login', passport.authenticate('login', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash : true
}));
/* GET Registration Page */
router.get('/signup', function(req, res){
res.render('register',{message: req.flash('message')});
});
/* Handle Registration POST */
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/home',
failureRedirect: '/signup',
failureFlash : true
}));
return router;
}
I am trying to redirect a user once he signs up or if the username is already present in the db, the function works well but I can not redirect and I am totally confused on what to do next.
Here is my passport file
var LocalStrategy = require('passport-local').Strategy;
var User = require('./models/user');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user);
});
// used to deserialize the user
passport.deserializeUser(function(user, done) {
done(null, user);
});
passport.use('local-signup', 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) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// 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({ 'email' : email }, function(err, user) {
// if there are any errors, return the error
if (err) {
return done(err);
}
if(user) {
if(user.validPassword(password)) {
return done(null, user);
} else {
return done(null, true, req.flash('signupMessage', 'That email is already in DB.'));
}
} else {
var newUser = new User();
newUser.email = email;
newUser.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
return done(err);
return done(null, newUser);
});
}
});
});
}));
}
and my route
app.post('/signup',passport.authenticate('local-signup', {
successRedirect : '/timeslot', // redirect to the secure profile section
failureRedirect : '/', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
I have also tried doing
app.post('/signup',function(req, res, next) {
passport.authenticate('local-signup', function(err, user, info) {
if (user) {
res.redirect('/timeslot');
}
else res.redirect('/');
})(req, res, next);
});
but it is not working at all. I am desperate to fix this but dont know how.
I met the same problems with passport redirects. So my code began work just as
app.get("/auth/facebook/callback", passport.authenticate("facebook", { failureRedirect: config.loginPage }), function(req,res) {
res.redirect(config.redirectAfterLogin);
});
I'm new to node express and passport so I'm not sure what I'm missing. I'm trying to use a custom callback as all I want is a json response from my registration strategy. Currently I keep getting the following error "Missing credentials". I've been at it for a while now and I'm stuck.
Here is my controller:
app.post('/services/authentication/registration', function(req, res, next) {
console.log('before authentication')
passport.authenticate('local-registration', function(err, user, info) {
console.log('authentication callback');
if (err) { return res.send({'status':'err','message':err.message});}
if (!user) { return res.send({'status':'err','message':info.message});}
if (user!=false) { return res.send({'message':'registration successful'});}
})(req, res, next);
},
function(err, req, res, next) {
return res.send({'status':'err','message':err.message});
});
And my passport strategy:
passport.use('local-registration', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
console.log('credentials passed to passport' + email + '' + password)
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// 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
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, {message: 'User already exists'});
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
I dont think you should send "req" as a parameter to the authentication function. take a look at this example from the passport docs:
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);
});
}
));
I'm using passportJS and I'm wanting to supply more than just req.body.username and req.body.password to my authentication strategy (passport-local).
I have 3 form fields: username, password, & foo
How do I go about accessing req.body.foo from my local strategy which looks like:
passport.use(new LocalStrategy(
{usernameField: 'email'},
function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Unknown user' });
}
if (password != 1212) {
return done(null, false, { message: 'Invalid password' });
}
console.log('I just wanna see foo! ' + req.body.foo); // this fails!
return done(null, user, aToken);
});
}
));
I'm calling this inside my route (not as route middleware) like so:
app.post('/api/auth', function(req, res, next) {
passport.authenticate('local', {session:false}, function(err, user, token_record) {
if (err) { return next(err) }
res.json({access_token:token_record.access_token});
})(req, res, next);
});
There's a passReqToCallback option that you can enable, like so:
passport.use(new LocalStrategy(
{usernameField: 'email', passReqToCallback: true},
function(req, email, password, done) {
// now you can check req.body.foo
}
));
When, set req becomes the first argument to the verify callback, and you can inspect it as you wish.
In most common cases we need to provide 2 options for login
with email
with mobile
Its simple , we can take common filed username and query $or by two options , i posted following snippets,if some one have have same question .
We can also use 'passReqToCallback' is best option too , thanks #Jared Hanson
passport.use(new LocalStrategy({
usernameField: 'username', passReqToCallback: true
}, async (req, username, password, done) => {
try {
//find user with email or mobile
const user = await Users.findOne({ $or: [{ email: username }, { mobile: username }] });
//if not handle it
if (!user) {
return done(null, {
status: false,
message: "That e-mail address or mobile doesn't have an associated user account. Are you sure you've registered?"
});
}
//match password
const isMatch = await user.isValidPassword(password);
debugger
if (!isMatch) {
return done(null, {
status: false,
message: "Invalid username and password."
})
}
//otherwise return user
done(null, {
status: true,
data: user
});
} catch (error) {
done(error, {
status: false,
message: error
});
}
}));