TypeError: Cannot read property 'jwtoken' of undefined at Authenticate

Viewed 335

I am trying to authenticate the user using jwt and found this error. This is a MERN project and I had to verify the user whose data I have stored in MongoDb before showing a secret page.

Other errors which VSCode is highlighting are:

1.When I hover on ._id (authentication.js)

const rootUser=await User.findOne({_id:verifyToken._id,"tokens.token":token})

Property '_id' does not exist on type 'string | JwtPayload'.

2.When I hover on req.rootUser(app.js)

res.send(req.rootUser)

Property 'rootUser' does not exist on type 'Request<{}, any, any, ParsedQs, Record<string, any>>

My code looks as follows:

app.js

const mongoose = require('mongoose')
const dotenv = require('dotenv')
const bcrypt = require('bcryptjs')
const jwt=require('jsonwebtoken')
const app = express()
const router = express.Router();
const port = 5000
const authenticate=require("./middleware/authenticate")

dotenv.config({ path: './config.env' })
const DB = process.env.DATABASE;
app.use(express.json());
const User = require('./model/userSchema')



mongoose
  .connect(DB, {
    useUnifiedTopology: true,
    useNewUrlParser: true,

  })
  .then(() => console.log('Database connected.'))
  .catch(err => console.log(err));





app.get('/', (req, res) => {
  res.send('Hello World!')
  console.log("hey")
})
app.post('/register', async (req, res) => {
  const { name, email, work, phone, password, cpassword } = req.body;
  if (!name || !email || !work || !phone || !password || !cpassword) {
    return res.status(422).json({ error: "Form Not Properly Filled" });
  }
  try {
    const userExist = await User.findOne({ email: email })
    if (userExist) {
      return res.status(422).json({ error: "Email ALready Exists" })
    }
    else if (password != cpassword) {
      return res.status(422).json({ error: "Password does not match" })
    }
    else {
      const user = new User({ name, email, work, phone, password, cpassword })
      await user.save()
      res.status(201).json({ message: "user registered successfully" })
    }



  } catch (error) {
    console.log(error);
  }




})

//login route
app.post('/signin', async (req, res) => {
  try {

    let token;

    const { email, password } = req.body;
    if (!email || !password) {
      return res.status(400).json({ error: "Please fill the data correctly" })
    }
    const userLogin = await User.findOne({ email: email })
    console.log(userLogin);
  
    if (userLogin) {
      const isMatch = await bcrypt.compare(password, userLogin.password)
      token = await userLogin.generateAuthToken();
      console.log(token)

      res.cookie("jwtoken",token,{
        expires:new Date(Date.now()+25892000000),
        httpOnly:true

      })
      if (!isMatch) {
        res.status(400).json({ error: "Invalid Credentials" })
      }
      else {
        res.status(200).json({ message: "Login Success" })
      }
    }
    else {
      res.status(400).json({ error: "Invalid Credentials" })
    }

  } catch (error) {
    console.log(error)
  }
})

//about page request

app.get('/about',authenticate,  (req, res) => {
  console.log("About")
  res.send(req.rootUser)
})
app.get('/forget', (req, res) => {
  res.cookie("harsh","test")
  res.send('Forget World!')
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

authenticate.js

const User=require("../model/userSchema")

const Authenticate=async (req,res,next)=>{
try {
    console.log(req.cookies)
    const token=req.cookies.jwtoken;
    console.log("below")
    const verifyToken =jwt.verify(token,process.env.SECRET_KEY)
    console.log(verifyToken)
    const rootUser=await User.findOne({_id:verifyToken._id,"tokens.token":token})
    if(!rootUser){
        throw new Error("User Not Found")
    }
    req.token=token;
    req.rootUser=rootUser;
    req.userID=rootUser._id;
    next();
} catch (error) {
    res.status(401).send('Unauthorized : No token provided')
    console.log(error)
}
}
module.exports=Authenticate;

userSchema.js

const mongoose=require('mongoose')
const bcrypt=require('bcryptjs')
const jwt=require('jsonwebtoken')

const userSchema=new mongoose.Schema({
     name:{
         type:String,
         required:true,
     },
     email:{
        type:String,
        required:true,
    },
    phone:{
        type:String,
        required:true,
    },
    work:{
        type:String,
        required:true,
    },
    password:{
        type:String,
        required:true,
    },
    cpassword:{
        type:String,
        required:true,
    },
    tokens:[
        {
            token:{
                type:String,
                required:true,
            }
        }
    ]
})


userSchema.pre('save' , async function(next){
    console.log("inside hash")
    if(this.isModified('password')){
        this.password=await bcrypt.hash(this.password,12)
        this.cpassword=await bcrypt.hash(this.cpassword,12)
    }
    next();
})

userSchema.methods.generateAuthToken = async function(){
    try {
        let token =jwt.sign({_id:this._id},process.env.SECRET_KEY)
        this.tokens=this.tokens.concat({token : token})
        await this.save();
        return token
    } catch (error) {
        console.log(error)
    }
}

const User=mongoose.model('USER',userSchema);
module.exports=User;
1 Answers

1. GENERATE JWT TOKEN WHEN USER LOGIN

Generate Token and Send this token with a response...

    router.post("/login", async (req, res) => {
      try {
        // checking username
        const user = await User.findOne({ email: req.body.email });
        !user && res.status(401).json("Wrong Username");
    
        // checking password
        const bytes = CryptoJS.AES.decrypt(user.password, process.env.SECRET_KEY);
        const originalPassword = bytes.toString(CryptoJS.enc.Utf8);
    
        // If password not match return respond
        originalPassword !== req.body.password &&
          res.status(401).json("Wrong Password");
    
        // Creating Json Web Token
    
        const accessToken = jwt.sign(
          { id: user._id, isAdmin: user.isAdmin },
          process.env.SECRET_KEY,
          { expiresIn: "5d" }
        );
    
        // stop sending password to respond
        const { password, ...info } = user._doc;
    
        // Returning User(info) , also sending accessToken
        res.status(200).json({ ...info, accessToken });
      } catch (err) {
        res.status(500).json(err);
      }
    });

2. VERIFY TOKEN MIDDLEWARE

Create this verify token function use as a MIDDLEWARE in your routes...

const jwt = require("jsonwebtoken");

function verify(req, res, next) {
  const authHeader = req.headers.token;
  if (authHeader) {
    const token = authHeader.split(" ")[1];
    jwt.verify(token, process.env.SECRET_KEY, (err, user) => {
      if (err) res.status(403).json("Token is not valid");
      req.user = user;
      next();
    });
  } else {
    return res.status(402).json("You are not authorized");
  }
}

module.exports = verify;

3. VERIFY-IN ROUTES AS AN MIDDLEWARE

const verify = require("../verifyToken");

// CREATE
router.post("/", verify, async (req, res) => {
  if (req.user.isAdmin) {
    const newList = new List(req.body);
    try {
      const savedList = await newList.save();
      res.status(201).json(savedList);
    } catch (error) {
      res.status(500).json(err);
    }
  } else {
    res.status(403).json("You are not allowed!");
  }
});

// DELETE
router.delete("/:id", verify, async (req, res) => {
  if (req.user.isAdmin) {
    try {
      await List.findByIdAndDelete(req.params.id);
      res.status(201).json("The list has been deleted");
    } catch (err) {
      res.status(500).json(err);
    }
  } else {
    res.status(403).json("You are not allowed!");
  }
});

CONCLUSION:-

  1. Create a token with jwt.sign when user login...
  2. Create a verify function in the root directory export this function...
  3. Require this function in routes file use as a middleware...
Related