Dondaj
Dondaj

Reputation: 35

Mongoose .findOne is not a function - using passport

I keep getting this error while attempting to use my local strategy by passport lib.

TypeError: UserModel.findOne is not a function

I have looked around for hours but can't seem to find a solution that works for my problem. Here is my user.model and auth.services files.

user.model

const mongoose = require('mongoose');
const validator = require('validator');
const uniqueValidator = require('mongoose-unique-validator');
const jwt = require('jsonwebtoken');

const cryptor = require('../services/bcrypt.services');
const authServices = require('../services/auth.services');

const Schema = mongoose.Schema;

const UserSchema = new Schema({

    email: {
        type: String,
        unique: true,
        trim: true,
        lowercase: true,
        required: [true, 'Email is required'],
        validate: {
            validator: function(email) {
                return validator.isEmail(email);
            },
            message: function (props) { `${props.value} is not an valid email` }
        }
    },
    password: {
        type: String,
        trim: true,
        minlength: [6, 'Password too short'],
        lowercase: true,
        required: true
    },

    conversations: [{ type: Schema.Types.ObjectID, ref: 'Conversation' }]
});

UserSchema.methods = {

    async _hashPassword(password) {
        this.password = await cryptor.hashAsync(password);
    },

    async authUser(password) {
        return await cryptor.compareAsync(password, this.password);
    },

    createToken() {
        return jwt.sign({
            _id: this._id
        }, authServices.privateKey);
    },

    toAuthJWT() {
        return {
            _id: this._id,
            email: this.email,
            token: this.createToken()
        };
    },

    toJSON() {
        return {
            _id: this._id,
            email: this.email
        }
    }

};

UserSchema.pre('save', async function (next) {
    if (this.isModified('password')) {
        this._hashPassword(this.password);
    }

    next();
});

UserSchema.plugin(uniqueValidator, { message: '{VALUE} already exists' });

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

auth.services

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const JWTStrategy = require('passport-jwt').Strategy;
const ExtractJWT = require('passport-jwt').ExtractJwt;
const UserModel = require('../user/user.model');
const fs = require('fs');



// LocalStrategy
let localStrategy = new LocalStrategy({ usernameField: 'email', passwordField: 'password' }, function(email, password, done) {

    UserModel.findOne({ email: email }, function(err, user) {
        if (err) {
            return done(err);
        } else if(!user) {
            // Invalid email
            return done(null, false);
        } else if(!user.authUser(password)) {
            // Invalid password
            return done(null, false);
        }

        return done(null, user);
    });
});

passport.use(localStrategy);


// JWTStrategy
// eslint-disable-next-line no-undef
const privateKEY = fs.readFileSync(__dirname + '/private.key', 'utf8');
// eslint-disable-next-line no-undef
const publicKEY = fs.readFileSync(__dirname + '/public.key', 'utf8');

let jwtStrategy = new JWTStrategy({
    jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
    secretOrKey: publicKEY
}, function(payload, done) {

    UserModel.findById(payload._id, function(err, user) {
        if (err) {
            return done(err);
        } else if(!user) {
            return done(null, false);
        }

        return done(null, user);
    });

});

passport.use(jwtStrategy);

module.exports = {
    authLocal: passport.authenticate('local', { session: false }),
    authJwt: passport.authenticate('jwt', { session: false }),
    privateKey: privateKEY
};

I can't see why it can't find the UserModel.findOne function, or maybe i am missing something.

Upvotes: 0

Views: 355

Answers (2)

Dondaj
Dondaj

Reputation: 35

Solved it. The problem was with the program flow. I used the auth.services in my user.model file to get ahold of my privateKey. This made me trying to use my model before it even were initialized.

Upvotes: 1

James
James

Reputation: 82096

In your schema, you aren't extending the existing methods you are completely overwriting them i.e.

UserSchema.methods = { ... }

This line assigns a new object to methods which completely wipes out any existing functions (like findOne) that Mongoose provides. If you want to add static functions to the schema then you can extend statics

UserSchema.statics.myFunction = () => { ... }

Upvotes: 1

Related Questions