Registration of New Users using passport - node.js

I'm working on a freecodecamp challenge. I'm trying to register a user and login the same user but couldn't do it successfully.
I've tried various methods by changing my code a couple of times but still was not successful.
// Register
app.route('/register').post((req, res, next) => {
db.collection('users').findOne({ username: req.body.username }, function (err, user) {
if(err) {
console.log('error')
next(err);
} else if (user) {
console.log('redirect to home-page')
res.redirect('/');
} else {
db.collection('users').insertOne({username: req.body.username, password: req.body.password}, (err, doc) => {
if(err) {
console.log('error after recored')
res.redirect('/');
} else {
console.log('error with user', doc);
next(null, user);
}
}
)
}
})},
passport.authenticate('local', { failureRedirect: '/' }), (req, res, next) => {
res.redirect('/profile');
});
I have the complete code here for your reference.
I should be able to register and it directs me to my profile.
Login successfully and redirect to the profile.

In the code that you have referenced, you seem to have a typo in the Passport local strategy handler.
passport.use(new LocalStrategy(
function(username, password, done){
db.collection('user').findOne({username: username}, (err, user) => {
The collection here should be users as the Register route creates a entry in the users collection.

Related

How do i test postman when i have passport authentication

Im trying to test using postman but i have a passport authentication which is blocking me from testing as it will redirect me to the login screen it is not authenticated.
How i can get a token or authenticate myself in postman to be able to test
I have tried to use /auth/local in postman but it just returns that i cant get the route
Passport.js
var LocalStrategy = require('passport-local').Strategy;
var { User } = require('../model/user.js');
var bcrypt = require('bcrypt');
module.exports = function (passport) {
passport.use(new LocalStrategy(function (username, password, done) {
let query = { username: username };
User.findOne(query, function (err, user) {
if (err) throw err;
if (!user) {
return done(null, false,{ message: 'No user found' });
}
bcrypt.compare(password, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false,{ message: 'Wrong password' });
}
});
});
}));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
}
Route.js
router.get('/register', function (req, res) {
res.sendFile(__dirname + "/views/register.html");
});
router.post('/register', async (req, res) => {
var data = req.body;
var salt = await bcrypt.genSalt(10)
var hashedpw = await bcrypt.hash(data.password, salt)
const newUser = await User.create({
name: data.name,
email: data.email,
username: data.username,
password: hashedpw,
});
newUser.save();
req.flash('success', 'You are now registered and can log in');
res.redirect('/');
});
router.get('/login', function (req, res) {
res.locals.success = req.flash('success');
res.locals.error = req.flash('message');
res.render(__dirname + "/views/login.ejs");
});
router.post('/login', async (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
})(req, res, next);
});
router.get('/logout', async (req, res) => {
req.logout(function (err) {
if (err) { return next(err); }
req.flash('success', 'You are logged out');
res.redirect("/")
});
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/login');
}
}
Following this guide:
https://mevelix.com/articles/postman-auth-for-laravel,4
you have to create the Command:
php artisan make:command DevPostman
then in the newly created class, copy the content it is showed in the link,
inside the class namespace App\Console\Commands\DevPostmanCommand
Then you can execute the command:
php artisan dev:postman web
in this way you are creating a simulated session.
This is my ouput, for example:
you paste this output directly in PostMan, inside the Tab Pre-Request Scripts:
In this way you are allowed to avoid the login inside Postman, because you are simulating a session.
See the first link to have the complete code of the DevPostmanCommand class.

How to disallow disabled users from logging in, into a page using passport.js?

I've used a soft delete feature in mongodB to disable a user and not delete it permanently. Now, only enabled users can log in to the site while the disabled users can not log in to the site.
// Soft delete feature
exports.getDisabledUsers = function(req,res, next) {
User.find({active: false}, function(err, users) {
if (err) {
res.send(err);
}
res.json(users);
});
}
// Log In
exports.login = function (req, res, next) {
var userInfo = setUserInfo(req.user);
res.status(200).json({
token: 'JWT ' + generateToken(userInfo),
user: userInfo
});
};
// Passport.js
var localLogin = new LocalStrategy(localOptions, function (email, password, done) {
User.findOne({
email: email
}, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
error: 'Login failed. Please try again.'
});
}
user.comparePassword(password, function (err, isMatch) {
if (err) {
return done(err);
}
if (!isMatch) {
return done(null, false, {
error: 'Login failed. Please try again.'
});
}
return done(null, user);
});
});
});
Disabled users shouldn't be able to log in. Right now, they are able to log in.
While Disabling the user you can move that data to another collection, that way your disabled user cannot be able to login to your system
exports.disableUser = function (req, res, next) {
User.findByIdAndUpdate({_id:req.params._id}, {active: false}, function (err, users) {
if (err) {
res.send(err);
}
User.findByIdAndRemove(
{_id:req.params._id},
function(err, doc) {
if (doc) {
DisableUser.insertMany(doc, function(err, doc){
// your response
});
} else {
// your response
}
)
});
}
You have not checked user status is active or not. This can be done by adding a condition in code, or modifying mongo query and adding one more condition in findOne.
//CODE
if(!user.active) {
//RETURN USER IS NOT ACTIVE
}
//MONGO QUERY
User.findOne({
email: email,
active: true
}, function (err, user) {
//YOUR CODE
}
Role based login may create some complexity but this can be achieved simply by adding one more collection named disabledUsers
when admin disable any user then the click function do two things at the same time
1)add the email into disabledUser collection
2)delete the user from user collection
Then in your login function just check this way
disabledUser.findOne({email :email },
function (err ,user){
if(err) return done(err)
else{
if(!user){
user.findOne({email : email }
write your login stuff here the wau you r doing
}
else{return alert('user is disabled')}
}
})

Setting up Global sessions by using Passport Consumer strategy

I need some help with setting up Passport Consumer Strategy and integrating it into "locals" (Right now, we have the local strategy working just fine). We have tried several approaches but with no luck on it working 100%. The below code is not the complete code, we have taken out some of it so this post doesn't get too long. Any help with this would greatly be appreciate. There could be compensation as well if someone can get us over this hurdle.
So one question is, if the user is authenticated by the consumer key and secret, how does Passport store the session variables so they are used throughout the site?
Second question, how do we handle the user after it passes the authentication process?
Both local and consumer need to be working.
Consumer key and secret using a POST by a Provider <- I can show some of the post if needed.
This needs to be OAuth1 Only, as of right now, OAuth2 isn't an option.
This is for a single sign-on authentication.
I can supply a consumer session output if needed.
Ultimately, we would like the local strategy and the consumer strategy working with the same "locals" global variables. As far as I can tell, we can authenticate the consumer, retrieve the user from our DB, create a session and can tell if user is "ensureAuthenticated".
Here is what we have working right now.
Local strategy is authenticating correctly.
We render the pages with these local variables:
"Omitted most of the code to save time."
//=================================================================
// The Authentication Module will bind to POST /login route
//=================================================================
authentication.initLocalStrategyRoutes(app);
passport.authenticate('local', {successReturnToOrRedirect: '/', failureRedirect: '/login'});
...
function renderPage(req, res, pageName, pageTitle){
res.render(pageName, {
pageName: pageTitle,
username: req.user ? req.user.username : '',
...
Consumer strategy is authenticating by a POST request from a "Provider"
We have tried adding the Consumer strategy to the authentication.
server.js
//=================================================================
// The Authentication Module will bind to POST /login route
//=================================================================
authentication.initLocalStrategyRoutes(app);
ADDED -> authentication.initConsumerStrategyRoutes(app);
passport.authenticate('local', {successReturnToOrRedirect: '/', failureRedirect: '/login'});
ADDED -> passport.authenticate('consumer', {successReturnToOrRedirect: '/', failureRedirect: '/login'});
authentication.js (omitted code)
module.exports = function(siteConfig, defaultRedirectPage, server, sessionStore, log) {
var passport = require('passport')
...
, ConsumerStrategy = require('passport-http-oauth').ConsumerStrategy
, TokenStrategy = require('passport-http-oauth').TokenStrategy
, LocalStrategy = require('passport-local').Strategy;
var auth = {};
var authenticationRedirects = { successRedirect: '/', failureRedirect: '/login' };
passport.serializeUser(function(user, done) {done(null, user);});
passport.deserializeUser(function(obj, done) {done(null, obj);});
auth.authenticate = function(email, password, callback) {
email = email.toLowerCase();
userController.findUserByUsernameWithPermissions(email,
function(err, user) {
if (err) return callback(err);
if (!user) return callback(null, null, 'Incorrect username.');
bcrypt.compare(password, user.password_hash, function(err, res) {
if(err){return callback(err);
} else if (!res) {return callback(null, null, 'Incorrect password.');
} else {if (user.account_state>0) {callback(null, user);} else {return callback(null, null, '/reset?rand='+user._id);}}
});
}
);
}
auth.initLocalStrategyRoutes = function(app){
passport.use(new LocalStrategy(auth.authenticate));
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (!user) return res.send({success: false, message: info});
req.logIn(user, function(err) {
if (err) { return next(err); }
res.send(req.user);
});
}) (req, res, next);
});
}
auth.initConsumerStrategyRoutes = function(app){
// passport.use(new LocalStrategy(auth.authenticate));
console.log('app: ', app)
passport.use('consumer', new ConsumerStrategy(
function(key, done) { console.log('starting ConsumerStrategy');
dbConsumerKey.findByConsumerKey({consumerKey: key}, function(err, consumerKey) {
if (err) { return done(err); }
if (!consumerKey) {
var errCode = dbError.find({name:'no_resource_link_id'}, function(err, errorCodes) {
console.log('statusText: ', errorCodes[0]["statusText"]);
return errorCodes[0]["statusText"];
});
return done(null, errCode);
} else {
if (!consumerKey[0]["consumerKey"]) { return done(err); }
if (!consumerKey[0]["consumerSecret"]) { return done(err); }
// return done(null, consumerKey[0]["consumerKey"], consumerKey[0]["consumerSecret"]);
return done(null, consumerKey[0], consumerKey[0]["consumerSecret"]);
}
});
},
function(requestToken, done) {
dbRequestTokens.find(requestToken, function(err, token) {
console.log('inside requestToken');
if (err) { return done(err); }
var info = { verifier: token.verifier,
clientID: token.clientID,
userID: token.userID,
approved: token.approved
}
done(null, token.secret, info);
});
},
function(timestamp, nonce, done) {
done(null, true)
}
));
};
auth.initTokenStrategyRoutes = function(app){}
auth.addUser = function(username, email, password, callback){auth.authenticate(username, "pass", callback);}
return auth;
};
The authentication.js strategy does validate the consumer key and secret. but it doesn't create the session variable we are wanting. We would like the consumer strategy code to be in the authentication.js file.
Now here is another approach, we created a separate files called consumerkey.js
This direction works to a point. We can output the passport session either on the screen or on the command line.
var passport = require('passport')
exports.launchLti = [
passport.authenticate('consumer', { session: false/true [tried both] }),
function(req, res) {
db.findByStudentUserId({lis_person_contact_email_primary:
req.body.lis_person_contact_email_primary}, function(err, user) {
req.logIn(user, function(err) {
req.user.username = user[0].lis_person_contact_email_primary;
...
// req.session.save(function(){
// res.redirect('/classes');
res.redirect(200,'/');
// });
});
})
// res.render('launch', {launch: launch});
}
}]
I solved this issue by changing some of my code structure.
app.pst('/launch/lti/:id', function(req, res, next) {
passport.authenticate('consumer', {failureRedirect: '/login'}),
dbConsumerKey.findByStudentUserId({},
function(err, user) {
if (err) console.log(err, user);
req.logIn(user, function(err) {
if (err) return err;
ADDED -> req.session.valid = true;
ADDED -> res.redirect('/');
});
}
});
});
and modifying the render page function to adapt to the incoming information.
function renderPage(req, res, pageName, pageTitle){
...
this is where the locals are created
...
this allowed me to use my current local strategy as is and adding a totally different strategy route but making the session correctly.

Webpage has too many redirect during passport js logout

I implement passport js in mean stack with following ways and I get this webpage has too many redirect when logout button is click. Not sure what is wrong with it.
exports.signin = function (req, res, next) {
passport.authenticate('local', function (err, user, info) {
if (err || !user) {
res.status(400).send(info);
} else {
// Remove sensitive data before login
user.password = undefined;
req.login(user, function (err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
})(req, res, next);
};
module.exports = function (app, db) {
// Serialize sessions
passport.serializeUser(function (user, done) {
done(null, user);
});
// Deserialize sessions
passport.deserializeUser(function (user, done) {
request(options, function (err, response, user) {
done(err, user);
});
});
}
exports.signout = function (req, res) {
req.logout();
res.redirect('/');
};
What happens when you return a 400, do you load an error page? I've seen redirect loops where the user fails to authenticate and then the error page tries to authenticate again.
In this case you are logging out. Is this user permitted to see the next page after logout when they are logged out?
Take a look at your dev tools and post the sequence of requests. Could shed some light on what the redirect loop actually is.

node js express4 and passport js lengthy sign in

I am using express 4 with passport js to handle authentication of users.
The front end is Angular JS.
I am basically facing two problems:
1- sign in is lengthy, it takes up to 15 seconds to sign in.
2- once logged in, if i restart the node js server and refresh the page I am back to the signin page even though a cookie is set in the browser.
This is what i have in the backend
passport.serializeUser(function (user, done) {
done(null, user._id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
user.password = undefined;
done(err, user);
});
});
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: messages['116']});
}
user.comparePassword(password, function (err, isMatch) {
if (err) {
return done(err);
}
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: messages['116']});
}
});
});
}));
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('a very hard to guess string'));
app.use(session({
secret: 'a very hard to guess string'
}
));
app.use(passport.initialize());
app.use(passport.session());
The following is the login route:
router.post('/signin', function (req, res, next) {
var result = _.cloneDeep(SwissArmyKnife.resultObjSkel);
var username = req.body.username;
var password = req.body.password;
if (_.isEmpty(username)) {
result.error.reasons.push(SwissArmyKnife.messages['118']);
}
if (_.isEmpty(password)) {
result.error.reasons.push(SwissArmyKnife.messages['119']);
}
if (!_.isEmpty(result.error.reasons)) {
return res.json(200, result);
}
passport.authenticate('local', function (err, user, info) {
if (err) {
return next(err);
}
if (user) {
req.login(user, function (err) {
if (err) {
return next(err);
}
result.result = true;
return res.json(200, result);
})
}
if (info) {
result.error.reasons.push(info.message);
return res.json(200, result);
}
})(req, res, next);
});
when debugging the above code i notice a huge delay when the code reaches
passport.authenticate('local', function (err, user, info) {
what could be the problem???
what am i doing wrong?
Thanks in advance.
The reason you're seeing the sign-in page after restarting your server is because you are using the memory store for your sessions. As you've noticed this only has so much usefulness and you should use some persistent store instead (e.g. redis).

Resources