I'm working with node 4.3.1, express 4.13.1 and an authentication tool is the local-passport. I'm trying to post login form data by ajax. so I want to show error message without page refresh. but the first step is killing me.
view:
<form id="login_form" action="#">
<input type="hidden" id="csrf" name="_csrf" value="{{_csrfToken}}">
<input id="email" name="email" type="email" placeholder="Email">
<input id="password" name="password" type="password" placeholder="Password">
<button type="" id="forLogin">Login</button>
</form>
//POST Ajax
$('#forLogin').on('click', function(e){
e.preventDefault();
var data= {};
data.email = $('#email').val();
data.password = $('#password').val();
data._csrf = $('#csrf').val();
$.ajax({
type: 'POST',
url: '/login',
data: JSON.stringify(data), // node.js accepts request but responds 403
// data: $('#login_form').serialize(),
// don't accept any request
dataType: 'json',
// headers: {'X_CSRF_TOKEN':'{{_csrfToken}}'},
// not working too
success: function(result){
console.log('success');
if(!result){
console.log('No result');
}
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
}
});
});
If I use data: JSON.stringify(data) , the firefox inspector shows very suspicious parameter:
{"email":"test#gmail.com","password":"test","_csrf":"wOEsa4s2-I9dmSQuT9djm0kyrrp9WcZWj6U0"}:""
Even if this parameter passes well, I'm not sure it will work.
and In these cases: data: $('#login_form') or data:data
I don't get any response. but parameters seems plausible and key: attr pairs look neatly.
router.js
router.post('/login', function(req, res, next){
passport.authenticate('local-login', function(err, user, info){
console.log(req.body);
if (err) { return next(err); }
if (!user) {
console.log('authentication fail');
return res.json({ajaxMsg: 'authentication fail'});
}
req.logIn(user, function(err) {
if (err) { return next(err); }
// Redirect if it succeeds
return res.redirect('/');
});
})
});
passport.js
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
User = require('../models/User.js'),
bcrypt = require('bcrypt');
passport.serializeUser(function(user, done){
done(null, user.email);
});
passport.deserializeUser(function(email, done){
User.findOne(email, function(err, user){
done(err, user);
});
});
passport.use('local-login',
new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(req, email, password, done){
User.findOne({'email': email}, function(err, user){
if(err) return done(err);
if(!user){
console.log('wrong email');
req.flash('email', req.body.email);
return done(null, false, req.flash('error_messages', 'No user found'));
}
if(!user.authenticate(password)){
console.log('wrong password');
req.flash('email', req.body.email);
return done(null, false, req.flash('error_messages', 'Password does not Match'));
}
console.log('Login Success');
return done(null, user);
});
})
);
module.exports = passport;
I realized that there is no way to use connect-flash message without page refresh so I trying to replace other logics It's hard to understand how done() method works
Instead of
if (err) { return next(err); }
Try
if (err) { return res.json({error: err}); }
And If you get an error, then you'll have to sort that out but I believe that's your problem. Is your request returning a 404 or 500 on your logger?
Done is the callback it uses which populates the req.session object.
Also I believe you're not using next() properly. Unless your /login is some sort of middleware and you're expecting something else to happen after it ends
I solved the problem.
router.post('/login', function(req, res, next) {
if(req.body.email.length == 0 || req.body.password.length == 0) {
return res.json({error: 'enter a id and a pw'});
}
passport.authenticate('local-login', function(err, user, info) {
if (err) {
return res.json({srverror: err});
}
// Redirect if it fails
if (!user) {
return res.json({error: info.msg});
}
if (user) {
req.logIn(user, function(err) {
if (err) { return res.json({srverror: err}); }
// Redirect if it succeeds
res.send({redirect: '/'});
});
}
})(req, res, next);
});
(req, res, next) is the code I needed.
but I cannot fully understand why It works.
Related
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);
});
I'm building an app in Node, using Passport and local signup and sign in strategies. I just keep running into an issue. All the required modules etc. are there. The following sign in routine works fine:
passport.use('local-signin', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : 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('message', 'User not found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('message', 'Wrong password.'));
return done(null, user);
});
}));
However, the following sign up routine does not:
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : true
}, function(req, email, password, done) {
console.log("signing up")
User.findOne({ 'local.email' : email }, function(err, user) {
if (err) {
return done(err);
} else if (user) {
return done(null, false, req.flash('message', 'That email address is already registered.'));
} else {
var newUser = new User();
}
// save the user
newUser.save(function(err) {
if (err) {
console.log("Error saving new user profile: " + err);
} else {
return done(null, newUser, req.flash('message', 'User account created'));
}
});
});
}))
Both routines are called within routes.js:
// POST : SIGNUP
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect: '/error',
failureFlash: true
}));
// POST : SIGNIN
app.post('/signin', passport.authenticate('local-signin', {
successRedirect: '/profile',
failureRedirect: '/',
failureFlash: true
}));
Any ideas where it might go wrong? As is, posting to /signup continuously results in a failureRedirect. My head is getting kinda sore from banging on the screen...
The only thing you need to change is:
if (!user.validPassword(password))
To
if (user.validPassword(password) === false)
I know, if (!user.validPassword(password)) is in examples on Passport.js official docs, but it is wrong.
I have just lost 2 hours of my life, figuring this out.
Use this code it will helps you to fix your problem
passport-authentication.js
var express=require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/user');//user is schema
var Verify = require('./verify');//verify is a file where the user is verified
/* GET users listing. */
router.get('/', Verify.verifyOrdinaryUser,function(req, res, next) {
User.find({},function(err,user){
if(err) throw err;
res.json(user);
});
});
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username,Email:req.body.Email}),
req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
if(req.body.firstname) {
user.firstname = req.body.firstname;
}
if(req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save(function(err,user) {
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
verify.js
var User = require('../models/user');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('../config.js');
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, {
expiresIn: 3600
});
};
exports.verifyOrdinaryUser = function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secretKey, function (err, decoded) {
if (err) {
var err = new Error('You are not authenticated!');
err.status = 401;
return next(err);
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
var err = new Error('No token provided!');
err.status = 403;
return next(err);
}
};
hope this helps for you...
I'm trying to authenticate a user when logging in to website. Upon login, the username and password get sent to a post route from an ajax request on the client side. The problem is that there is an old userID attached to req.user._id that I cannot remove. This old userID continues to authenticate any user I try.
This is my passport settings on the server:
var passport = require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;
var strategy = new BasicStrategy(function(username, password, callback) {
User.findOne({
username: username
}, function(err, user) {
if (err) {
callback(err);
return;
}
if (!user) {
return callback(null, false, {
message: 'Incorrect username.'
});
}
user.validatePassword(password, function(err, isValid) {
if (err) {
return callback(err);
}
if (!isValid) {
return callback(null, false, {
message: 'Incorrect password.'
});
}
return callback(null, user);
});
});
});
passport.use(strategy);
app.use(passport.initialize());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
This is my route:
app.post('/authenticate', passport.authenticate('basic', { session: false }), function(req, res) {
console.log("req.user:", req.user);
var id = req.user._id;
res.json({
message: 'You have been authenticated',
userID: id
});
});
On the client side, I am sending a POST request like this:
function getLogin(loginObject) {
$.ajax({
type: "POST",
url: "/authenticate",
dataType : "json",
data: { username: loginObject.username, password: loginObject.password }
})
.done(function(result) {
console.log("Authenticated");
loginUserID = result.userID;
})
.fail(function(jqXHR, error, errorThrown) {
};
This is a screenshot of my terminal showing the userID that won't delete:
req.user: { _id: 588a834c08c038342e420568,
username: 'mm',
password: '$2a$10$Khp1wUkHvLLn6ZVBNlLqM.Mtio0ZZ4dznGPQs0ECqf.snhUl44OxK',
__v: 0 }
From my understanding, the req.user._id is created as soon as the username and password get's authenticated. So I cannot understand what is holding on to this userID.
Your help is appreciated.
I'm making a form login by passportJs and it always return failureRedirect. I have search in stack overflow for this issue, but still not have the correct answer. Here is my code:
Form making form jade:
form(method='post', action='/users/login', enctype='multipart/form-data')
.form-group
label Username
input.form-control(name='username', type='text' placeholder='Enter Username')
.form-group
label Password
input.form-control(name='password', type='password' placeholder='Enter password')
input.btn.btn-default(name='submit', type='submit', value='Login')
Router Hanlde is using express framework form Nodejs and passport middleware:
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function(username, password, done) {
User.getUserByUsername(username, function(err, user) {
if (err) throw err;
if (!user) {
console.log('Unknown 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 {
console.log('Invalid Password');
return done(null, false, {
message: 'Invalid Password'
});
}
});
});
}
));
router.post('/login', passport.authenticate('local', {
failureRedirect: '/users/login',
failureFlash: 'Invalid username or password'
}), function(req, res) {
console.log('Authentication Successful');
req.flash('success', 'You are logged in ');
res.redirect('/');
});
Looking at getUserByUsername function you shared in comments, it looks like you are not making call to callback function of getUserByUsername in correct way and therefore it is not getting user object resulting into failure redirect. The function you shared was:
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
Changing it to following should fix your issue:
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, function(err, user) {
callback(err, user);
});
}
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);
});
});