The promise chain works like this: We check if a user with the submitted email exists in the database. If the user is found, the hash of the user's password is checked. In this lesson, we'll improve our code. We'll actually make the code for checking emails and passwords part of the User schema itself. For this, we'll write a method called findUserByCredentials(), which has two parameters, email and password, and returns either a user object or an error. Mongoose allows us to do this, and in order to add a custom method, we'll need to set it on the statics property on the desired schema: // models/user.js const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true }, password: { type: String, required: true, minlength: 8 } }); // we're adding the findUserByCredentials methods to the User schema // it will have two parameters, email and password userSchema.statics.findUserByCredentials = function findUserByCredentials (email, password) { }; module.exports = mongoose.model('user', userSchema); Save All that's left is to write this method's code. In the future, we'll use the method like so: User.findUserByCredentials('elisebouer@tripleten.com', 'EliseBouer1989') .then(user => { // we get the user object if the email and password match }) .catch(err => { // otherwise, we get an error }); Save The findUserByCredentials() Method In order to find a user by email, we'll need the findOne() method, which takes email as an argument. The findOne() method belongs to the User model, so we'll call this method using the this keyword: // models/user.js userSchema.statics.findUserByCredentials = function findUserByCredentials (email, password) { // trying to find the user by email return this.findOne({ email }) // this — the User model .then((user) => { // not found - rejecting the promise if (!user) { return Promise.reject(new Error('Incorrect email or password')); } // found - comparing hashes return bcrypt.compare(password, user.password); }); }; module.exports = mongoose.model('user', userSchema); Save The findUserByCredentials() method should not be an arrow function. This is so that we can use this. Otherwise, the value of this would be statically set, as arrow functions remember the value of this from their initial declaration. Now we need to add an error handler for whenever the hashes don't match. We'll write the code for this in a further then() function. But first, let's take a quick look at how we should NOT do this: // models/user.js userSchema.statics.findUserByCredentials = function findUserByCredentials (email, password) { // trying to find the user by email return this.findOne({ email }) .then((user) => { // not found - rejecting the promsie if (!user) { return Promise.reject(new Error('Incorrect email or password')); } // found - comparing hashes return bcrypt.compare(password, user.password); }) .then((matched) => { if (!matched) // rejecting the promise return user; // oh - the user variable is not in this scope }); }; module.exports = mongoose.model('user', userSchema); Save In the second then(), we're returning a user object which doesn't exist in that scope as it was left back in the previous then(). In order to solve this problem, we should organize our promise chain differently. Let's add a then() handler to bcrypt.compare(): // models/user.js const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const { Schema } = mongoose; const userSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true }, password: { type: String, required: true, minlength: 8 } }); userSchema.statics.findUserByCredentials = function findUserByCredentials (email, password) { return this.findOne({ email }) .then((user) => { if (!user) { return Promise.reject(new Error('Incorrect email or password')); } return bcrypt.compare(password, user.password) .then((matched) => { if (!matched) { return Promise.reject(new Error('Incorrect email or password')); } return user; // now user is available }); }); }; module.exports = mongoose.model('user', userSchema); Save The method is ready. Now we can apply it to the authentication handler: // controllers/users.js module.exports.login = (req, res) => { const { email, password } = req.body; return User.findUserByCredentials(email, password) .then((user) => { // authentication successful! user is in the user variable }) .catch((err) => { // authentication error res .status(401) .send({ message: err.message }); }); };