I'm trying to confirm users email addresses by sending an activator code to their email address. when user clicked on activator URL (GET method), server will compare activator code + username and try to handle it.
I'm using GET method like this:
router.get('/activator/:username/:activator', function(req, res, next){
passport.authenticate('activator', function(err, user, info){
if (err) {console.log('Error info: ', info);}
else if (!user) {console.log('User not found: ' , info)}
else {console.log('User activated')}
res.redirect('/');
})(req, res, next)
});
And activator.js is:
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
module.exports = function(passport){
passport.use('activator', new LocalStrategy({
usernameField: 'username',
passwordField: 'activator'
},
function(username, password, done) {
User.findOne({username: username , activator: password},
function(err, user){
if (err){
return done(null, false, 'User not found.');
}
user.activate = true;
user.save(function (err) {
if (err) return handleError(err);
return done(null, user, 'Persistence Registration successful');
});
});
})
);
};
But server response is: { message: 'Missing credentials'}
It seems passport js and GET method params has some conflicts.
Am i right? what should i do for that?
Problem solved!
As I said, problem was for GET method & passport connection.
passport function only read from req.query which is only on POST method but GET method is using req.params.
So I changed my application code to :
router.get('/activator/:username/:activator', function(req, res, next){
req.query = req.params; // GET to POST simulator!
passport.authenticate('activator', function(err, user, info){
if (err) {console.log('Error info: ', info);}
else if (!user) {console.log('User not found: ' , info)}
else {console.log('User activated')}
res.redirect('/');
})(req, res, next)
});
your Strategy fields are not valid, replace it with email and password and send same parameters from client side
module.exports = function(passport) {
passport.use('activator', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
},
function(username, password, done) {
User.findOne({
username: username,
activator: password
},
function(err, user) {
if (err) {
return done(null, false, 'User not found.');
}
user.activate = true;
user.save(function(err) {
if (err) return handleError(err);
return done(null, user, 'Persistence Registration successful');
});
});
}));
};
Related
First, i have this in my route, i need to use Passport to Authenticate the User Sign Up Process :
router.post('/user/signup', passport.authenticate('local.signup',{
successRedirect: '/user/profile',
failureRedirect: '/user/signup',
failureFlash: true
}));
I'm learning Node JS from Youtube Video, in the tutorial, there is a step to create Folder called "config", and inside the "config" folder, there is a file called "passport.js".
The problem is, there is "req" parameter inside one of the function in this "passport.js". When i try to run my program, there is an error that said, "req is not defined". this is the source code of "passport.js" :
var express = require('express');
var passport = require('passport');
var User = require('../models/user');
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('local.signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallBack: true
}, function(req, email, password, done){ //here is the problem
console.log('REQ :');
console.log(req);
console.log('password :');
console.log(email);
console.log('email :');
console.log(password);
console.log('done :');
console.log(done);
req.checkBody('email','Invalid Email').notEmpty().isEmail();
req.checkBody('password','Invalid password').notEmpty().isLength({min:4});
var errors = req.validationErrors();
if(errors){
var message = [];
errors.forEach(function(error){
message.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email': email}, function(err, user){
if(err){
return done(err);
}
if(user){
return done(null, false, {message: 'Email is already in use.'});
}
var newUser = new User();
newUser.email = email;
newUser.password = newUser.encryptPassword(password);
newUser.save(function(err, result){
if(err){
return done(err);
}
return done(null, newUser);
});
});
}));
How to bring the req to fill the parameter in the passport.js ?
The parameter is called passReqToCallback, not passReqToCallBack (notice that the b needs to be lower-case).
I'm trying to get a handle on user authentication with PassportJS, and I cannot get it to work my database setup.
I'm using MongoDB without Mongoose, and I can't get the LocalStrategy module to work.
Hopefully my database queries aren't too cumbersome to read.
Local Strategy:
passport.use(new LocalStrategy(
function(username, password, done) {
//Fire up database
mongo.connect("mongodb://localhost:27017/formulas", function(e, db) {
if (e) {return next(e);}
var col = db.collection("users");
//Do a database query to find a record by username
col.findOne({"username": username}, function(err, user){
if (err) { return done(err);}
if(!user) {
return done(null, false, { message: "Please check your log in credentials." });
}
//if it exists call done() object with user information
bcrypt.compare(password, user.password, function(err, res){
if (err) throw err;
if (res == true) {
return done(null, {username: username, password: password});
} else {
return done(null, false, { message: "Invalid password."});
}
});
});
});
}));
I call passport.authenticate() like this:
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect:'/about',failureFlash: false}),
function(req, res){
console.log(req.body);
console.log(req.user);
console.log("The user was logged");
});
SerializeUser and deserializeUser look like this:
passport.serializeUser(function(user, done) {
done(null, user.username);
});
passport.deserializeUser(function(id, done) {
mongo.connect("mongodb://localhost:27017/formulas", function(e, db){
if (e) {return next(e);}
var col = db.collection("users");
col.findOne({"username": id}, function(err, user){
done(err, {"username": id});
});
});
});
When I call app.post(/login) I'm taken directly to /about and nothing is logged to the console so I'm not quite sure what's going wrong.
Advice on what to fix or how to troubleshoot is greatly appreciated.
Firstly when u serialize user object , then in deserialize also whole user object must be passed.
Consider the example below.
For routes :
router.post('/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); }
req.session.user = req.user;
return res.redirect('/home');
});
})(req, res, next);
});
For passport.js , place the localstrategy and passport in same folder
var passport = require('passport'),
session = require('express-session');
var local = require('./localstrategy.js');
module.exports = function (app) {
app.use(session({
secret: 'Site visit',
resave: true,
saveUninitialized: true,
cookie: { secure: false }
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done){
done(null, user);
});
passport.deserializeUser(function(user, done){
done(null, user);
});
local();
};
For local strategy :
'use strict';
var passport = require('passport'),
local = require('passport-local').Strategy;
var user;
// path where the db.js is placed
var db = require('./../db.js');
var ObjectId = db.getObjectID();
var bcrypt = require('bcrypt');
module.exports = function(){
passport.use(new local({
usernameField : 'username',
passwordField : 'password'
}, function(username, password, done){
var collection = db.getDb().collection('users');
collection.findOne({
username: username,
}, function (err, result) {
if(result == null){
cb(null, false);
}else {
bcrypt.compare(password, result.password, function (err, passRes) {
if (passRes == true) {
user = user;
done(err, user);
}else{
done(null, false, { message : 'Invalid Password'});
}
});
}
});
}));
};
I'm using passport local strategy like this:
Config:
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(email, password, done) {
UserPersistenceModel.findOne({ email: email }, function (err, user) {
if (err) return done(err);
if (!user) return done(null, false);
user.comparePassword(password, function(err, isMatch) {
if(err) return done(err);
if(!isMatch) return done(null, false);
return done(null, user);
});
});
}
));
My router definition looks like this:
var TokenRouter = function(app, passport, tokenSecret) {
//Create
app.post('/', function(req, res, next) {
console.log(req.body);
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (!user) {
console.log('Unsuccessful login!');
return res.status(401).json({ error: 'Login failed!' });
}
req.logIn(user, function(err) {
if (err) return next(err);
console.log('Successful login!');
//user has authenticated correctly thus we create a JWT token
var token = jwt.encode(user, tokenSecret);
res.json({ output : token });
});
})(req, res, next);
});
};
For some reasons I don't fully understand the passport "mechanism". The documentation doesn't look very detailled to me. One question is where the request object (this contains the body which contains the email and the password) is passed to my strategy. How does the strategy gets the email and the password (what's the "source object")?
The reason asking this is that I'd like to use the following inputModel instead of the request being passed to the strategy:
var TokenCreateInputModel = function(req) {
this.email = req.body.email;
this.password = req.body.password;
this.validate();
};
TokenCreateInputModel.prototype = Object.create(InputModel);
TokenCreateInputModel.prototype.validate = function() {
if(!this.email) throw new Error('Email is required!');
if(this.email.indexOf('#') == -1) throw new Error('Emailsyntax is wrong!');
if(!this.password) throw new Error('Password is required!');
};
module.exports = TokenCreateInputModel;
This inputmodel is converting the request and validating the data. I want to use this input model because it fits better to my architecture (I'm using such inputModels in all other cases ... just not with passport (because of the lack of my understanding), which seems to be inconsistent to me.
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);
});
}
));