Having an awful time trying to compare passwords using bcryptjs so I can sign a JWT but trying to login I can't compare to sign the token and send to the client.
Problem
I can hash a password and store into the DB, where I'm having issues is using the .compare() method and passing in the hash parameter. I'm not quite sure what to pass in as the hash value.
Technology:
NodeJS: 5.4.1
bcryptjs: 2.3.0
express: 4.14.0
body-parser: 1.15.2
MongoDB: 3.2.5
mongoose: 4.6.1
user.routes.js
var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
var salt = bcrypt.genSaltSync(10);
var config = require('../config/database');
User = require('../models/user.model.js');
// Create new User
router.post('/', function(req, res){
var user = req.body;
if(!req.body.email || !req.body.password){
res.json({success: false, message: 'Please pass email and password'});
} else {
User.addUser(user, function(err, user){
if(err){
res.send(err);
}
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(user.password, salt, function(err,hash){
user.password = hash;
user.save();
console.log('new user', user);
res.json({success: true, message: 'Create user successful'});
})
})
});
}
});
Getting errors during password compare:
// Authenticate a User
//email: test#test.com
//password: password
router.post('/login', function(req, res){
User.findOne({ email: req.body.email }, function (err, user){
if (err){
res.send(err);
}
if(!user){
res.json({ success: false, message: 'Authentication failed. User not found'});
} else if (user) {
// where does this hash value get defined and passed in?
bcrypt.compare(req.body.password, hash, function(err, res){
if(user.password != req.body.password){
console.log('password incorrect');
//res.json({ success: false, message: 'Authentication failed. Password incorrect'});
} else {
var token = jwt.sign({
email: user.email
}, config.secret, {
expiresIn: 60 // expressed in seconds
});
console.log('token contents', token);
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
});
}
});
});
The hash value that you have to pass to the compare method is the one you got when you called bcrypt.hash method. I suppose you saved that hash associated to the user in some DB, so you have to get that hash and pass it to compare method as second parameter.
I think you are doing wrong the comparison in the callback of the compare method. You shouldn't compare passwords, the compare method does that for you. You just have to check if res is true or false. If it is true, then passwords are the same, other case they are different.
If you have more doubts about the implementation in this article you have a very simple example about that:
https://solidgeargroup.com/password-nodejs-mongodb-bcrypt?lang=es
It is written with promises, but it's very easy to understand.
Related
im building a website in my free time using nodejs/Handlebars.js/mongodb(mongoose),
i didnt study any web developement lessons, and i dont know the right way to do things efficiently and securely.
so in this project, i stumbled upon a problem where i had to query in the database if email already exists or no if it does, it queries again if the username already exists or not, if it does exists the user can be registred to the databse. yes it gets the job done but im not satisfyied with this approach, it seems to be unprofessional and not secure.
so can you please tell me the right way to do it ?
this is the part where i think i ve done it the wrong way
//check for errors in Req.validation and push them to errors Array
if(valErrors){
for (var i = 0; i < valErrors.length; i++) {
errors.push(valErrors[i])
}
}
//check if the username submitted exists in the database
User.findOne({'username':username}, function (err, user) {
if(user)
{
errors.push({msg:"username is already in use!"})
res.render('user/register',{
errors:errors
});
}
//if the username is not in use already check if the email is in
//use
else {
User.findOne({'email':email}, function (err, user) {
if(user){
errors.push({msg:'email is already in use !'})
res.render('user/register',{
errors:errors
});
} //if the email doesnt exists too then register this //user
else{
var coins = new Coins()
var newUser = new User({
name: name,
email:email,
username: username,
password: password,
coins:coins.encryptcoins('0'),
joindate:getDate()
});
User.createUser(newUser, function(err, user){
if(err) throw err;
});
req.flash('success_msg', 'You are registered and can now login');
res.redirect('/user/login');
}
});
}
});
})
EDIT:
user Schema
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index:true,
required:true
},
password: {
type: String,
required:true
},
email: {
type: String,
required:true
},
name: {
type: String,
required:true
},
coins: {
type:String,
required:true
},
joindate: {
type:String,
required:true
},
orders: {
type:Array,
required:false
}
},{collection:'Users'});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
}
this is the whole code
var express = require('express');
var router = express.Router();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/users');
const ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn();
const ensureLoggedOut = require('connect-ensure-login').ensureLoggedOut();
var Coins = require('../models/coins');
// Register
router.get('/register',ensureLoggedOut, function(req, res){
res.render('user/register');
});
// Login
router.get('/login',ensureLoggedOut, function(req, res){
res.render('user/login');
});
// Register User
router.post('/register', function(req, res){
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
var password2 = req.body.password2;
console.log(email)
console.log(username)
// Validation
req.checkBody('name', 'Name is required').notEmpty();
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Email is not valid').isEmail();
req.checkBody('username', 'Username is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
req.checkBody('password2', 'Passwords do not match').equals(req.body.password);
//Error handling
var errors = [];
var valErrors = req.validationErrors()
//check for errors in Req.validation and push them to errors Array
if(valErrors){
for (var i = 0; i < valErrors.length; i++) {
errors.push(valErrors[i])
}
}
//check if the username submitted exists in the database
User.findOne({'username':username}, function (err, user) {
if(user)
{
errors.push({msg:"username is already in use!"})
res.render('user/register',{
errors:errors
});
}
//if the username is not in use already check if the email is in
//use
else {
User.findOne({'email':email}, function (err, user) {
if(user){
errors.push({msg:'email is already in use !'})
res.render('user/register',{
errors:errors
});
} //if the email doesnt exists too then register this //user
else{
var coins = new Coins()
var newUser = new User({
name: name,
email:email,
username: username,
password: password,
coins:coins.encryptcoins('0'),
joindate:getDate()
});
User.createUser(newUser, function(err, user){
if(err) throw err;
});
req.flash('success_msg', 'You are registered and can now login');
res.redirect('/user/login');
}
});
}
});
})
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);
});
});
router.post('/login',
passport.authenticate('local', {successReturnToOrRedirect: '/', failureRedirect:'/user/login',failureFlash: true}),
function(req, res) {
res.redirect('/');
});
router.get('/logout',ensureLoggedIn, function(req, res){
req.logout();
req.session.destroy();
res.redirect('/');
});
module.exports = router;
function getDate(){
var d = new Date()
return ("date: "+d.getDate()+"/"+(d.getMonth()+1)+"/" +d.getFullYear() + " time GMT+1: "+(d.getHours()+1)+":"+(d.getMinutes())).toString()
}
// replaced with Ensure loging in library !
// function ensureLoggedIn(req, res, next) {
// if(req.user){
// return next()
// }else{
// res.redirect('/user/login');
// }
// }
// function ensureLoggedOut(req, res, next) {
// if(!req.user){
// return next()
// }else{
// res.redirect('/');
// }
// }
In general, for a logical unit of work send to a Database Management System (DBMS) (i.e., MongoDB server), it is imperative to group the individual operations in a single transaction. This way, you can avoid inconsistencies that might result from concurrent user creation in your database.
To be more precise, in your project the registration process checks for the following:
Check if email exists
Check if username exists
If queries 1 and 2 returned an empty result set, register a new user
In essence, those 3 steps need to take place in an atomic fashion, which means that they occur as a single logical unit (Transaction). If not, in the extreme case that 2 concurrent clients try to register users with the same usernames, then your database will result with two users with the same username.
Therefore, you should update your code to do the following:
Initiate a transaction
Check for users with the given email (user_email) and or usernamae (user_name)
If the query of step 2 returned a user, then rollback the transaction; Otherwise, insert a new user with user_email and user_name.
Commit Transaction
I am not sure whether MongoDB supports Transactional Consistency, and this is one of the reasons that I suggested using an RDBMS. Also, if it doesn't, I am sure that you can figure out a schema that identifies a single user based on email/username and try to perform the registration as a transaction.
Finally, it is considered good practice to have most of the processing take place in the DBMS side with the use of Stored Procedures.
I hope this helps.
I am trying to send a welcome email after a user signs up with nodemailer and also adding the user to mongodb with passport.authenticate on the same post route. I am able to get this to work separately i.e. either sending email or adding the user to the database but can't seem to get them to work together. I am new to nodejs and would really appreciate any help. Here is the route I am trying to get to work:
router.post('/signup', function(req, res,next) {
async.waterfall([
function(done) {
passport.authenticate('signup', {
successRedirect: '/',
failureRedirect: '/signup',
failureFlash : true
});
},
function(user, done) {
var transporter = nodeMailer.createTransport({
service: 'SendGrid',
auth: {
user: 'user',
pass: 'password'
}
});
var mailOptions = {
to: user.email,
from: 'me#gmail.com',
subject: 'Welcome to the site',
html: '<p> This is html, did I render correctly?</p>'
};
transporter.sendMail(mailOptions, function(err){
done(err);
});
}
], function(err) {
res.redirect('/signup');
});
});
Here is the signup strategy with passport:
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
var bCrypt = require('bcrypt-nodejs');
module.exports = function(passport){
passport.use('signup', new LocalStrategy({
usernameField : 'email',
passReqToCallback : true
},
function(req, email, password, done) {
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({ 'email' : email }, function(err, user) {
// In case of any error, return using the done method
if (err){
req.flash('error','Email Already Exists',err.message);
return done(err);
}
// already exists
if (user) {
console.log('User already exists with username:');
return done(null, false, req.flash('error','Email 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.password = createHash(password);
newUser.email = req.param('email');
newUser.firstName = req.param('firstName');
newUser.lastName = req.param('lastName');
// save the user
newUser.save(function(err) {
if (err){
console.log('Error in Saving user: '+err);
return done(null, false, req.flash('error',err.message));
}
console.log('User Registration succesful');
return done(null, newUser);
});
}
});
};
// Delay the execution of findOrCreateUser and execute the method
// in the next tick of the event loop
process.nextTick(findOrCreateUser);
})
);
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
}
}
Thanks in advance for the help!
Why don't you move the email sending logic to the passport signup strategy?
I have read all the related questions and responses and still can't fix this issue. Please see the code below and help me understand why terminal is throwing 'undefined is not a function'.
For a rundown of the functions:
The query section looks up SQL gets the users PW from DB. Parse results gets just the pw and eliminates the 'key' from the key value pair. Move pw function is there just as a buffer so that compare PW will not execute until we have retrieved the pw to compare with.
I have been stuck on this for a while, any help is much appreciated. To see the running app, go here...a working un/pw combo are user5 1234, but bc of the error it will look up username, password, verify that its a match (the compare pw and the look up pw functions actually do work and tell you if its a existing pw and un combo, but when i try and return done(user, null) to the passport login route, it crashes...
https://[redacted].com/
var express = require('express');
var router = express.Router();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var db = require('../database');
var returnedPw;
var flash = require('connect-flash');
var session = require('express-session');
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 's',
user : 'n',
password : '',
database : 's'
});
//stripped credentioals
// Include User Model
var User = require('../models/user');
// Include Student Model
var Client = require('../models/client');
// Include Instructor Model
var Company = require('../models/company');
router.get('/signup', function(req, res, next) {
res.render('users/signup');
});
router.post('/signup', function(req, res, next){
// Get Form Values
console.log('starting post and making new user');
var first_name = req.body.first_name;
var last_name = req.body.last_name;
var street_address = req.body.street_address;
var city = req.body.city;
var state = req.body.state;
var zip = req.body.zip;
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
var password2 = req.body.password2;
var type = req.body.type;
// Form Field Validation
req.checkBody('first_name', 'First name field is required').notEmpty();
req.checkBody('last_name', 'Last name field is required').notEmpty();
req.checkBody('email', 'Email field is required').notEmpty();
req.checkBody('email', 'Email must be a valid email address').isEmail();
req.checkBody('username', 'Username field is required').notEmpty();
req.checkBody('password', 'Password field is required').notEmpty();
req.checkBody('password2', 'Passwords do not match').equals(req.body.password);
var errors = req.validationErrors();
if(errors){
res.render('users/signup', {
errors: errors,
first_name: first_name,
last_name: last_name,
street_address: street_address,
city: city,
state: state,
zip: zip,
email: email,
username: username,
password: password,
password2: password2
});
} else {
var newUser = new User({
email: email,
username:username,
password: password,
type: type
});
console.log('calling post to database file to receive new user:' + newUser)
// THIS IS WHERE WE ARE POSTING THE NEW USER TO THE DATABASE!!!
db.postUsers(newUser);
var newClient = new Client({
first_name: first_name,
last_name: last_name,
address: [{
street_address: street_address,
city: city,
state: state,
zip: zip
}],
email: email,
username:username
});
if(type == 'client'){
//User.saveClient(newUser, newClient, function(err, user){
// console.log('Client created');
///}); works but replacing w sql
} else {
var newCompany = new Company({
first_name: first_name,
last_name: last_name,
address: [{
street_address: street_address,
city: city,
state: state,
zip: zip
}],
email: email,
username:username
});
//works but replacing w sql
//User.saveCompany(newUser, newCompany, function(err, user){
// console.log('Company created');
//});
//sql save function
console.log('calling sql save..');
//db.postUsers(newUser, newClient);
}
req.flash('success','User added');
res.redirect('/');
}
});
<!--//// -USER AUTH SECTION- \\\\--!><!--//// -USER AUTH SECTION- \\\\--!><!--//// -USER AUTH SECTION- \\\\--!>
/*
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function (err, user) {
done(err, user);
});
}); */
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
router.post('/login',passport.authenticate('local',{failureRedirect:'/', failureFlash:'Wrong Username or Password'}), function(req, res){
req.flash('success','You are now logged in');
var usertype = req.user.type;
res.redirect('/'/*+usertype+'s/classes' */);
});
passport.use(new LocalStrategy(
function(username, password, done ) {
console.log('in users the username is ' + username)
connection.query('SELECT password FROM t_user WHERE username = ?', username, function(err, user) {
parseResults(user, done);
});// end query
function parseResults(user, done) {
Object.keys(user)[0];
var key = Object.keys(user)[0];
user[key];
var storedPw = user[key];
for(var i in storedPw){
returnedPw = storedPw[i];
}
console.log('returnedPw is defined here ' +returnedPw);
movePw(returnedPw, done);
}// end function
var candidatePassword = password;
function movePw (returnedPw, done) {
if (returnedPw ) {
User.comparePassword(candidatePassword, returnedPw, function(err, isMatch) {
if (err) return done(err);
if(isMatch) {
//return done(null, user);
// req.flash('success','User Access Granted');
//console.log('go head')
user = username;
return done(null, user);
//done(null, user);
//notifyOuterScope();
//return true;
} else {
console.log('Invalid Password');
// Success Message
req.flash('failureFlash','User Access Denied. False Password');
return done(null, false, { message: 'Invalid password' });
}
});
}
else {console.log('return PW not defined')}
}
}// end outer function ?
));//end passport
// Log User Out
router.get('/logout', function(req, res){
req.logout();
// Success Message
req.flash('success', "You have logged out");
res.redirect('/');
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/')
}
/* COMPARING PASSWORDS */
/* where are we returning the password from the user db profile?
bcrypt.hash('mypassword', 10, function(err, hash) {
if (err) { throw (err); }
bcrypt.compare('mypassword', hash, function(err, result) {
if (err) { throw (err); }
console.log(result);
});
});
*/
module.exports = router;
The code is a working example of using SQL and passport.js with node. I was having difficulty using the Local Strategy required for passport (using sql commands instead of mongodb commands that you see in most passport documentation), and it turns out the reason is because I wasn't passing the correct variables/ was also passing in unnecessary variables.
I corrected it above. Instead of using the User.FindOne Mongo db query in local strategy, this is an example of how to do the same username/ password querys using SQL, within passport local strategy. There isn't much documentation on using SQL and passport / node.
I am building an app using the MEAN stack and I'm fairly new to it. My current issue is that I am trying to reference my Surf Model to a User Model in express. What I want it to do is simply create a new Surf Object with a reference to the user that created it. My current set up spits out an error when I try to create a new Surf object on a POST request. By the way I am also using jsonwebtokens for authentication. Not sure if that has anything to do with it, but just mentioning it. Any help is appreciated.
/models/surf.js
// surf.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//SURF SCHEMA
// ============================================
var SurfSchema = new Schema({
title: String,
longitude: Number,
latitude: Number,
comment: String,
created: { type: Date, default: Date.now },
user_id: {type: Schema.ObjectId, ref: 'User'}
});
var Surf = mongoose.model('Surf', SurfSchema);
module.exports = Surf;
/models/user.js
//USER MODEL
// Require packages for User model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt-nodejs');
//USER SCHEMA
// ============================================
var UserSchema = new Schema({
name: String,
username: {type: String, required: true, index: {unique: true}},//No duplicate usernames
password: {type: String, required: true, select: false}//Do not return password
});
//HASH PASSWORD
// ============================================
//Hash password before saving
UserSchema.pre('save', function(next){
var user = this;
//Hash password only if the password has been changed or is new
if(!user.isModified('password')) return next();
//Generate Salt
bcrypt.hash(user.password,null, null, function(err,hash){
if(err) return next(err);
//Change the password to the hash version
user.password = hash;
next();
});
});
//Create method to compare a given password with the database hash
UserSchema.methods.comparePassword = function(password){
var user = this;
return bcrypt.compareSync(password,user.password);
};
//Create User model out of userSchema
var User = mongoose.model('User', UserSchema);
module.exports = User;
/routes/api.js
//api.js
var bodyParser = require('body-parser');
var User = require('../models/user');
var Surf = require('../models/surf');
var jwt = require('jsonwebtoken');
var config = require('../config');
//superSecret secret for creating tokens
var superSecret = config.secret;
//Pass in app and express to use express object for express.Router()
module.exports = function(app, express){
// Instance of express Router
var apiRouter = express.Router();
//API AUTHENTICATE ROUTE
// ====================================================================
//Route for authenticating user at /api/authenticate
apiRouter.post('/authenticate', function(req, res){
//find the user and select username and password explicitly
User.findOne({
username: req.body.username
}).select('name username password').exec(function(err, user){
if(err) throw err;
// no user with that username was found
if(!user){
res.json({success: false, message: 'Authentication failed. User not found'});
}else if (user) {
//check if password is a match
var validPassword = user.comparePassword(req.body.password);
if(!validPassword) {
res.json({success: false, message: 'Authentication failed. Wrong password'});
}else {
//if user is found and password matches
var token = jwt.sign({
name: user.name,
username: user.username
}, superSecret, {
expiresInMinutes: 1440 //Expires in 24 hours
});
//return the information including token as json
res.json({
success: true,
message: 'Here is your token',
token: token
});//End response json
}
}
});
});//End Post authenticate
//TOKEN MIDDLEWARE
// ====================================
//Middleware to use before for all requests(Token varification)
apiRouter.use(function(req,res,next){
//logging
console.log('A visitor has arrived');
//Check Header OR Url parameters OR POST parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
//Decode the token
if(token){
//Verifies secret and checks expiration
jwt.verify(token, superSecret, function(err, decoded){
if(err){
return res.json({success: false, message: 'Failed token authentication'});
}else {
//If token checks out, save the request to be used in other routes
req.decoded = decoded;
next();//User may continue forward if they have a valid token
}
});
}else {
//if there is no token return 403(access forbidden) and an error message
return res.status(403).send({success: false, message: 'No token Provided'});
}
});//End Middleware
//TEST ROUTE
// ====================================
//Test Route
apiRouter.get('/', function(req,res){
res.json({message: "Welcome to the API"});
});
//API ROUTES USERS
// ====================================================================
//routes that end with /users --------------------
apiRouter.route('/users')
//CREATE a user on /api/users
.post(function(req, res){
//creat a new user instance from User model
var user = new User();
//set the users information that comes from requests
user.name = req.body.name;
user.username = req.body.username;
user.password = req.body.password;
//save user and check for errors
user.save(function(err){
if(err){
//A duplicate was entered
if(err.code == 11000){
return res.json({success: false, message: 'A user with that username exists'});
}else {
return res.send(err);
}
}
res.json({message: 'User created!'});
});//End save
})//End Post
//GET all users at /api/users
.get(function(req, res){
User.find(function(err,users){
if(err){
res.send(err);
}
//Return all users
res.json(users);
});
});//End Get
//routes that end with /users:user_id --------------------
apiRouter.route('/users/:user_id')
//GET a single user at /users/:user_id
.get(function(req,res){
User.findById(req.params.user_id, function(err,user){
if(err) res.send(err);
// return the user
res.json(user);
});
})//End Get
//UPDATE the user with this id at /users/:user_id
.put(function(req,res){
//use user model to find the user we want
User.findById(req.params.user_id, function(err,user){
if(err) res.send(err);
//update the users info only if it is new(no blanks)
if(req.body.name) user.name = req.body.name;
if(req.body.username) user.username = req.body.username;
if(req.body.password) user.password = req.body.password;
//save user
user.save(function(err){
if(err) res.send(err);
// return message
res.json({message: 'User has been updated!'});
});//End save
});//End find by id
})//End Post
//DELETE a user with this id at /users/:user_id
.delete(function(req,res){
User.remove({
_id: req.params.user_id
}, function(err, user){
if(err) res. send(err);
res.json({message: 'Succesfully deleted user'});
});
});
//api endpoint to get user information
apiRouter.get('/me', function(req, res){
res.send(req.decoded);
});
//API ROUTES SURF
// ====================================================================
//routes that end with /surf --------------------
apiRouter.route('/surf')
//CREATE a surf on /api/surf
.post(function(req, res){
//create a new instance of the surf model
var surf = new Surf();
User.findOne({username: decoded.username}, function(err, user){
req.user = user;
next()
})
//set the surf information that comes from requests
surf.title = req.body.title;
surf.longitude = req.body.longitude;
surf.latitude = req.body.latitude;
surf.comment = req.body.comment;
surf.user_id = req.user._id;
//save user and check for errors
surf.save(function(err){
if(err)
res.send(err);
res.json({message: 'Surf Session Created!'});
});//End save
})//End Post
//GET all surf sessions at api/surf
.get(function(req, res){
// Use the Surf model to find all surf sessions
Surf.find({ }, function(err, surfSesh) {
if (err)
res.send(err);
res.json(surfSesh);
});
})//
return apiRouter;
};
I tried surf.user_id = req.user._id;
but I keep getting an error of cannot
read property '_id of undefined'
In this else block right here:
}else {
//If token checks out, save the request to be used in other routes
req.decoded = decoded;
next();//User may continue forward if they have a valid token
}
You have a decoded token, which means you should have access to the username. What you then have to do is get the user model, and set it to the req object, and only afterwards call next() e.g.
User.findOne({username: decoded.username}, function(err, user){
req.user = user;
next()
})
---EDIT----
//TOKEN MIDDLEWARE
// ====================================
//Middleware to use before for all requests(Token varification)
apiRouter.use(function(req,res,next){
//logging
console.log('A visitor has arrived');
//Check Header OR Url parameters OR POST parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
//Decode the token
if(token){
//Verifies secret and checks expiration
jwt.verify(token, superSecret, function(err, decoded){
if(err){
return res.json({success: false, message: 'Failed token authentication'});
}else {
//If token checks out, save the request to be used in other routes
req.decoded = decoded;
// GET USER HERE
User.findOne({username: decoded.username}, function(err, user){
req.user = user;
next()
})
}
});
}else {
//if there is no token return 403(access forbidden) and an error message
return res.status(403).send({success: false, message: 'No token Provided'});
}
});//End Middleware
On a node.js server I am using bcrypt to hash a password which is received by a user via a POST request and then store the hash in a database. The hashing function function takes longer to compute than creation of the saving of the hash and other parameters to the database, so I need to use a promise to executing the save after the hashing function has finished. I am using the Q library for this purpose, but I'm not sure how to do this. I am using mongoose for data modelling.
async bcrypt hashing function
var bcrypt = require('bcrypt');
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(req.body.password, salt, function(err, hash) {
// Store hash in DB
});
});
});
POST route
app.post('/api/users', function(req, res) {
var newUser = new User({
email: req.body.email,
name: req.body.name,
password: hash
});
newUser.save(function(err) {
if(!err) {
return res.send({ status: 'User created' });
} else {
if(err.name == 'ValidationError') {
res.statusCode = 400;
res.send({ error: 'Bad Request' });
} else {
res.statusCode = 500;
res.send({ error: 'Internal Server Error' });
}
}
});
});
I would figure the population of the newUser variable and newUser.save() call would be the argument of then(), but how do I make the bcrypt hashing function issue the promise and pass the hash?
You could simply move your database queries, to inside the callback of the hash, so that when the hash call back is ready it would then save it.
var bcrypt = require('bcrypt');
app.post('/api/users', function(req, res) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(req.body.password, salt, function(err, hash) {
var newUser = new User({
email: req.body.email,
name: req.body.name,
password: hash
});
newUser.save(function(err) {
if(!err) {
return res.send({ status: 'User created' });
} else {
if(err.name == 'ValidationError') {
res.statusCode = 400;
res.send({ error: 'Bad Request' });
} else {
res.statusCode = 500;
res.send({ error: 'Internal Server Error' });
}
}
});
});
});
});
Or use the synchronous call of bcrypt.hashSync but synchronous is not good practice when trying to work with Node.
But it could be like password: bcrypt.hashSync(req.body.password, salt)
If I understand correctly what you're asking, you want to save the user, after the password is hashed?