Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript User Authentication With Express and Mongo User Registration Storing Passwords Securely

Damian McCarthy
Damian McCarthy
3,656 Points

My mongoose Schema variables are coming back undefined which making the hash not work.

This is my user.js I can view the json file and everything is there when I do res.send(req.body); but in here it is saying it is undefined, any ideas?

This is the error I am getting including the console log of the JSON strings

undefined
undefined
Error: data and salt arguments required
    at Object.hash (D:\Folder\Code\Nymadic\nymadic.com\node_modules\bcrypt\bcrypt.js:138:17)
    at model.UserSchema.pre (D:\Folder\Code\Nymadic\nymadic.com\models\user.js:37:12)
    at callMiddlewareFunction (D:\Folder\Code\Nymadic\nymadic.com\node_modules\kareem\index.js:427:23)
    at model.next (D:\Folder\Code\Nymadic\nymadic.com\node_modules\kareem\index.js:58:7)
    at _next (D:\Folder\Code\Nymadic\nymadic.com\node_modules\kareem\index.js:106:10)
    at process.nextTick (D:\Folder\Code\Nymadic\nymadic.com\node_modules\kareem\index.js:452:38)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickCallback (internal/process/next_tick.js:180:9)
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const UserSchema = new mongoose.Schema({
    userName: {
        type : String,
        unique : true,
        required : true,
        trim : true
    },
    password: {
        type: String,
        required: true
    },
    firstName: {
        type: String,
        required: true,
        trim: true
    },

    lastName: {
        type: String,
        required: true,
        trim: true
    },
    email: {
        type : String,
        unique : true,
        required : true,
        trim : true
    }
});

// hash password before saving to database
UserSchema.pre('save', (next) => {
    const user = this;
    console.log(UserSchema.userName);
    console.log(UserSchema.password);
    bcrypt.hash(user.password, 10, (err, hash) => {
        if(err) {
            return next(err);
        }
        user.password = hash;
        next();
    })
});


const User = mongoose.model('User', UserSchema);
module.exports = User;

index.js file

const express = require('express');
const router = express.Router();
const User = require('../models/user.js')


// Home Routes

router.get('/', (req, res, next) => {
    res.render('index');
});

// About Routes

router.get('/about', (req, res, next) => {
    res.render('about', {title : '| About'});
});

// Tools Routes

router.get('/tools', (req, res, next) => {
    res.render('tools', {title : '| Tools'});
});

router.post('/tools', (req, res, next) => {
    var domain = req.body.domain;
    res.end(domain);
});

// Login Routes

router.get('/login', (req, res, next) => {
    res.render('login', {title : '| Login'});
});

router.post('/login', (req, res, next) => {
    res.send(req.body);
    res.end;
});

// Registration Routes 

router.get('/registration', (req, res, next) => {
    res.render('registration', {title : '| Registration'});
});

router.post('/registration', (req, res, next) => {
    res.send(req.body);
    // Check if all fields are filled
    if (req.body.userName && req.body.password && req.body.confirmPassword && req.body.firstName && req.body.lastName && req.body.email) {

        // Confirm Password is the same
        if ( req.body.password != req.body.confirmPassword) {
            const err = new Error ("Passwords don't match!");
            err.status = 400;
            return next(err);
        }

        const userData = {
            userName: req.body.userName,
            password: req.body.password,
            firstName: req.body.firstName,
            lastName: req.body.lastName,
            email: req.body.email
        };

        // Use schema 'create' method to insert document into Mongo
        User.create(userData, (error, user) => {
            if (error) {
                return next(error);
            } else {
                return res.redirect('/profile');
            }
        });
    } else {
        const err = new Error("All Fields Required.");
        err.status = 400;
        return next(err);
    }
});

// Profile Routes

router.get('/profile', (req, res, next) => {
    res.render('profile');
});
module.exports = router;

app.js file

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const path = require('path');
const mongoose = require('mongoose');

// Mongodb connection
mongoose.connect("mongodb://localhost:27017/nymadic");
const db = mongoose.connection
// Mongo error
db.on('error', console.error.bind(console, 'connection error:'));

// Body Parser and Cookie Parser
app.use(bodyParser.urlencoded({ extended:false }));
app.use(cookieParser());

// Static Files
app.use(express.static(__dirname + '/public'));

// Pug Render Engine
app.set('view engine', 'pug');

// Routes
const mainRoutes = require('./routes');
const wikiRoutes = require('./routes/wiki');

app.use(mainRoutes);
app.use('/wiki', wikiRoutes);

app.listen(8080, () => {
    console.log('Nodejs is running on port 8080...');
  }); 

3 Answers

Hi Damian,

Try swapping the arrow function in the pre save hook for a normal function. e.g

UserSchema.pre('save', (next) => {
//...
}

Becomes:

UserSchema.pre('save', function(next)  {
// ...
}

this works differently in arrow functions. Good explanation

Hope this helps :)

Damian McCarthy
Damian McCarthy
3,656 Points

You are a god... I have been stuck on this for days. Should I not use arrow functions?

I feel your pain. If I hadn't come across this issue before, I would never have guessed.

Its fine to use arrow functions, just be be careful when using 3rd party libraries and when using this.

If you are using them client side, be aware of browser support

Glad it worked anyway :)

Hi Damian,

2 things that may help.

In your user.js file, instead of doing:

console.log(UserSchema.userName);    
console.log(UserSchema.password);

Try:

console.log(user.userName);
console.log(user.password);

You are trying to access the userName and password properties on the UserSchema object. But they don't exist. You should be accessing the userName and password properties on the user object instead.


In your index.js file, on this line:

router.post('/registration', (req, res, next) => {
    res.send(req.body);
    // Check if all fields are filled
    // ...
}

It looks like you are sending a response straight away so the rest of the function doesn't get run. What happens if you comment this line out?

EDIT: Didn't fully read the question, I see you did that for debugging. Try the changes anyway and see what gets logged.

Hope this helps :)

Damian McCarthy
Damian McCarthy
3,656 Points

Yeah its still the same issue, even when I just trying to console log

console.log(user);

This comes back empty

Chai Chong Teh
Chai Chong Teh
25,709 Points

I am following what the videos have been showed, other than this:

// mongodb connection, updated by referring to docs
mongoose.connect("mongodb://localhost:27017/bookworm",
                { 
                  useNewUrlParser: true,
                  useCreateIndex: true,
                });
const db = mongoose.connection;

which ultimately leads me to "error is not defined" page when submitted. Any ideas why?

Chai Chong Teh
Chai Chong Teh
25,709 Points

Also, when opening up the mongo db, there are no instances being created.

Hi Chai,

Is the error message in the browser or the console?

I would recommend creating a new forum post, and posting your full app.js, user.js and index.js files. Plus the full error message and what steps you took to produce it.

That way other students can help as well.