Search code examples
node.jsexpressmongoosepassport.js

TypeError Passport JS username property undefined


I am a beginner in Reactjs and nodejs trying to make my first full stack app. In my postjob schema I want the username of the current logged in user in the publisher field. Passport has a req.user command to get details of the current user but whenever I try to use this it gives the type error.If you guys need any other file let me know

postjob schema

const mongoose=require('mongoose')

const postjobtemplate= new mongoose.Schema({

    jobtitle:{
        type:String,
        required:true
    },
    company:{
        type:String,
        required:true
    },
    officelocation:{
        type:String,
        required:true
    },
    jobtype:{
        type:String,
        required:true
    },
    publisher:{           ///<=HERE
        type:String,
        required:true
    },
    date:{
        type:Date,
        default:Date.now
    }
})

module.exports=mongoose.model("postjobtable",postjobtemplate)

routes js

router.post('/postjob',async(request,response,next)=>{
    const postjob=new postjobtemplatecopy({
        jobtitle:request.body.jobtitle,
        company:request.body.company,
        officelocation:request.body.officelocation,
        jobtype:request.body.jobtype,
        publisher:request.user.username, //////<=HERE

    })
    postjob.save()
    .then(data=>{
        response.json(data)

    })
    .catch(error=>{
        response.json(error)
    })
});

router.post("/login", (req, res, next) => {
    passport.authenticate("local", (err, user, info) => {
      if (err) throw err;
      if (!user) res.send("No User Exists");
      else {
        req.logIn(user, (err) => {
          if (err) throw err;
          res.status(200).send("Successfully Authenticated");
    
        });
      }
    })(req, res, next);
  });

server js

const express =require('express')
const app=express()
const mongoose=require('mongoose')
const dotenv=require('dotenv')
const routes=require('./routes/routes')
const cors=require('cors')
const passport=require("passport")
const passportlocal = require("passport-local").Strategy;
const bodyParser=require("body-parser")
const session=require("express-session") 
const cookieparser=require('cookie-parser')

dotenv.config();
mongoose.connect(process.env.DB_CONNECT,{useNewUrlParser:true},()=>
console.log("database connected")
);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(express.urlencoded({ extended: true }));

app.use(cors({
    origin:'http://localhost:3000',
    credentials:true
}))

app.use(session({
    secret:'secret',
    resave:true,
    saveUninitialized:true
}))

app.use(cookieparser("secret"))
app.use(passport.initialize());
app.use(passport.session());
require('./passport-config')(passport);
app.use(express.json())
app.use('/api',routes)

app.listen(4002,()=>console.log("server running on port 4002"))

module.exports = app;

passport config

const User = require("./models/user");
const bcrypt = require("bcryptjs");
const localStrategy = require("passport-local").Strategy;

module.exports = function (passport) {
  passport.use(
    new localStrategy((username, password, done) => {
      User.findOne({ username: username }, (err, user) => {
        if (err) throw err;
        if (!user) return done(null, false);
        bcrypt.compare(password, user.password, (err, result) => {
          if (err) throw err;
          if (result === true) {
            return done(null, user);
          } else {
            return done(null, false);
          }
        });
      });
    })
  );

  passport.serializeUser((user, cb) => {
    cb(null, user.id);
  });
  passport.deserializeUser((id, cb) => {
    User.findOne({ _id: id }, (err, user) => {
      const userInformation = {
        username: user.username,
      };
      cb(err, userInformation);
    });
  });
};

Solution

  • You are getting typeError because username is not being sent/received properly. Change this line in your post route: publisher: request.user.username, for this: publisher: request.body.username,(I assume you are sending it from the front-end as username, if not, it would be useful to include your request from React in your code) that way you are actually receiving the data you're sending from the front end. Also, if you are using a different field other than username, you need to specify it in your passport strategy like this:

    passport.use(
        "yourStrategyName", //here you are naming the strategy to be used in your route
        new localStrategy( {
        usernameField: "publisher", //here you are telling passport to use "publisher" as a username
      },(publisher, password, done) => {
          User.findOne({ publisher }, (err, user) => { //changed to the field name in database
            if (err) throw err;
            if (!user) return done(null, false);
            bcrypt.compare(password, user.password, (err, result) => {
              if (err) throw err;
              if (result === true) {
                return done(null, user);
              } else {
                return done(null, false);
              }
            });
          });
        })
      );
    

    And in your route.js:

      router.post("/login", (req, res, next) => {
        passport.authenticate("yourStrategyName", (err, user, info) => { //include the strategy name as the first parameter
          if (err) throw err;
          if (!user) res.send("No User Exists");
          else {
            req.logIn(user, (err) => {
              if (err) throw err;
              res.status(200).send("Successfully Authenticated");
        
            });
          }
        })(req, res, next);
      });