I was trying out passport local authentication by following a tutorial. Everything seems fine but I’m getting this error when I make a request using Postman:
[nodemon] 1.18.11 [nodemon] to restart at any time, enter `rs` [nodemon] watching: *.* [nodemon] starting `node server.js` body-parser deprecated bodyParser: use individual json/urlencoded middlewares server.js:17:10 (node:6336) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect. Started listening on PORT: 8080 events.js:167 throw er; // Unhandled 'error' event ^ TypeError: Cannot read property 'password' of undefined at model.userSchema.methods.validPassword.password [as validPassword] (F:Web ProjectsLocalAuthuserModel.js:20:50) at F:Web ProjectsLocalAuthpassport.js:34:21 at F:Web ProjectsLT1Kqob5UDEML61gCyjnAcfMXgkdP3wGcgGdBcFel.js:4672:16 at F:Web ProjectsLT1Kqob5UDEML61gCyjnAcfMXgkdP3wGcgGdBcFry.js:4184:12 at process.nextTick (F:Web ProjectsLT1Kqob5UDEML61gCyjnAcfMXgkdP3wGcgGdBcFry.js:2741:28) at process._tickCallback (internal/process/next_tick.js:61:11) Emitted 'error' event at: at F:Web ProjectsLT1Kqob5UDEML61gCyjnAcfMXgkdP3wGcgGdBcFel.js:4674:13 at F:Web ProjectsLT1Kqob5UDEML61gCyjnAcfMXgkdP3wGcgGdBcFry.js:4184:12 at process.nextTick (F:Web ProjectsLT1Kqob5UDEML61gCyjnAcfMXgkdP3wGcgGdBcFry.js:2741:28) at process._tickCallback (internal/process/next_tick.js:61:11) [nodemon] app crashed - waiting for file changes before starting...
Here is my user schema:
const mongoose = require('mongoose'); const bcrypt = require('bcrypt-nodejs'); const Config = require ('./config'); mongoose.connect (Config.dbUrl); let userSchema = new mongoose.Schema({ local : { email: String, password: String, }, }); userSchema.methods.generateHash = password => { return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); }; userSchema.methods.validPassword = password => { return bcrypt.compareSync(password, this.local.password); }; module.exports = mongoose.model('User', userSchema);
And this is my server.js file:
const express = require ('express'); const session = require ('express-session'); const mongoose = require ('mongoose'); const bodyParser = require ('body-parser'); const cookieParser = require ('cookie-parser'); const morgan = require ('morgan'); const flash = require ('connect-flash'); const passport = require ('passport'); const PassHandler = require('./passport'); const app = express (); const port = process.env.PORT || 8080; app.use (morgan ('dev')); app.use (bodyParser ({extended: false})); app.use (cookieParser ()); app.use ( session ({secret: 'borkar.amol', saveUninitialized: true, resave: true}) ); //Initialize Passport.js app.use (passport.initialize ()); app.use (passport.session ()); app.use (flash ()); //Global Vars for flash messages app.use((req, res, next) => { res.locals.successMessage = req.flash('successMessage'); res.locals.errorMessage = req.flash('errorMessage'); res.locals.error = req.flash('error'); next(); }); PassHandler(passport); //Middleware to check if the user is logged in. const isLoggedIn = (req, res, next) => { if(req.isAuthenticated()) { return next(); } res.status(400).json({ message: 'You are not authenticated to acces this route.' }); } app.get('/', (req, res) => { res.json({ message: 'Local Auth API v0.1.0'}); }); app.post('/signup', passport.authenticate('local-signup', { successRedirect: '/user', failureRedirect: '/signup', failureFlash: true, })); app.post('/login', passport.authenticate('local-login', { successRedirect: '/user', failureRedirect: '/', failureFlash: true, })); app.get('/user', isLoggedIn, (req, res) => { res.json({ user: req.user, message: "User is logged in."}); }); app.listen (port, () => { console.log (`Started listening on PORT: ${port}`); });
Here is the Passport strategy I’m using:
passport.use ( 'local-login', new LocalStrategy ( { usernameField: 'email', passwordField: 'password', passReqToCallback: true, }, function (req, email, password, done) { User.findOne ({'local.email': email}, function (err, user) { if (err) return done (err); if (!user) return done ( null, {message: 'User not found.'}, req.flash ('errorMessage', 'No user found.') ); if (!user.validPassword (password)) return done ( null, {message: 'Invalid email or password.'}, req.flash ('errorMessage', 'Oops! Wrong password.') ); // all is well, return successful user return done (null, user); }); } ) );
I’ve no idea whats going wrong to be honest. please help.
**Update:**The signup route and signup strategy is working fine. Only the /login
route is giving problem.
Advertisement
Answer
I rewrote most of the script, and it works now! Here is the code.
const express = require ('express'); const session = require ('express-session'); const bodyParser = require ('body-parser'); const cookieParser = require ('cookie-parser'); const mongoose = require ('mongoose'); const passport = require ('passport'); const LocalStrategy = require ('passport-local').Strategy; const User = require ('./UserModel'); const dbUrl = 'url'; const port = process.env.PORT || 9000; const app = express (); app.use (bodyParser.json ()); app.use (bodyParser.urlencoded ({extended: true})); app.use (cookieParser ()); app.use ( session ({secret: 'borkar.amol', saveUninitialized: false, resave: false}) ); app.use (passport.initialize ()); app.use (passport.session ()); mongoose.connect (dbUrl, {useNewUrlParser: true}, () => { console.log ('Successfully connected to hosted database.'); }); passport.serializeUser ((User, done) => { //console.log ('SERIALIZEUSER: ', User._id); done (null, User._id); }); passport.deserializeUser ((id, done) => { User.findById (id, (err, User) => { //console.log ('DESERIALIZEUSER: ', User); done (err, User); }); }); passport.use ( 'signup', new LocalStrategy ( { usernameField: 'email', passwordField: 'password', }, (email, password, done) => { process.nextTick (() => { User.findOne ({email: email}, (err, foundUser) => { if (err) return done (err); if (foundUser) { return done (null, false, { message: 'The email is already registered.', }); } else { let newUser = new User (); newUser.email = email; newUser.password = newUser.hashPassword (password); newUser.save (err => { if (err) console.error ('Error when writing to database', err); }); return done (null, newUser, { message: 'User has been registered successfully.', }); } }); }); } ) ); passport.use ( 'login', new LocalStrategy ( { usernameField: 'email', }, (email, password, done) => { User.findOne ({email: email}, (err, foundUser) => { if (err) return done (err); if (!foundUser) { return done (null, false, { message: 'Invalid Username or Password.', }); } if (!foundUser.comparePassword (password)) { return done (null, false, { message: 'Invalid Username or Password.', }); } return done (null, foundUser); }); } ) ); //Routes ---> app.get ('/user', (req, res, next) => { if (req.isAuthenticated ()) { res.json ({user: req.user}); return next (); } res.status (400).json ({message: 'Request is not authenticated.'}); }); app.post ( '/signup', passport.authenticate ('signup', { successRedirect: '/user', failureMessage: true, successMessage: true, }) ); app.post ( '/login', passport.authenticate ('login', { successRedirect: '/user', failureMessage: true, successMessage: true, }) ); app.post ('/logout', (req, res) => { if (req.user) { req.session.destroy (); req.logout (); res.clearCookie ('connect.sid'); return res.json ({message: 'User is now logged out.'}); } else { return res.json ({message: 'Error: No user to log out.'}); } }); app.listen (port, () => { console.log (`Started listening on PORT: ${port}`); });