Getting an error "Cannot read properties of undefined (reading 'id') "

Viewed 28

I am creating a webtoken for my backend API and to update my database . Even though the token and ID given to it are correct, it's return an error “token not valid” in the POSTMAN. When I checked the console it showed an error stating that “TypeError: Cannot read properties of undefined (reading 'id')”.The code to it is shown below.

const jwt = require("jsonwebtoken");

const verifyToken = (req, res, next) => {
  const authHeader = req.headers.token;
  if (authHeader) {
    const token = authHeader.split("")[1];
    jwt.verify(token, process.env.JWT_SEC, (err, user) => {
      if (err) res.status(403).json("Token is not valid!");
      req.user = user;
      next();
    });
  } else {
    return res.status(401).json("YOu are not authenticated!");
  }
};
const verifyTokenAndAuthorization = (req, res, next) => {
  verifyToken(req, res, () => {
    if (req.user.id === req.params.id || req.user.isAdmin) {
      next();
    } else {
      res.status(403).json("You are not allowed to do that!");
    }
  });
};

module.exports = { verifyToken,verifyTokenAndAuthorization };



the code to the user module is given below

const User = require("../models/User.js");
const { verifyTokenAndAuthorization } = require("./verifyToken.js");
const router = require("express").Router();

//UPDATE
router.put("/:id", verifyTokenAndAuthorization, async (req, res) => {
  if (req.body.password) {
    req.body.password = CryptoJS.AES.encrypt(
      req.body.password,
      process.env.PASS_SEC
    ).toString();
  }
  try {
    const updatedUser = await User.findByIdAndUpdate(
      req.params.id,
      { $set: req.body, },
      { new: true }
    );
    res.status(200).json(updatedUser)
  } catch (err) {
    res.status(500).json(err);
  }
});
module.exports = router;

1 Answers

In your verifyToken() function you call another function jwt.verify() like so:

jwt.verify(token, process.env.JWT_SEC, (err, user) => {
      if (err) res.status(403).json("Token is not valid!");
      req.user = user;
      next();
    });

What is happening is jwt.verify() has found an error. So when it invokes your callback function:

(err, user) => {
      if (err) res.status(403).json("Token is not valid!"); // this is the problem!
      req.user = user;
      next();
    }

You are saying if there is an error, send a response of 403. Okay fine. BUT nothing stops your code from running after this point. So you have sent a 403 response, but are still setting req.user = user (which is probably undefined) and calling next()

What is next()? You have defined next as:

() => {
    if (req.user.id === req.params.id || req.user.isAdmin) {
      next();
    } else {
      res.status(403).json("You are not allowed to do that!");
    }
  }

So req.user is undefined, and you are trying to see if req.user.id === req.params.id. At runtime this is actually equivalent to undefined.id === req.params.id

So in short, you need to make sure you are exiting your code correctly. A simple solution to this a small change to your current code:

jwt.verify(token, process.env.JWT_SEC, (err, user) => {
      if (err) {
        // Could throw an error here, catch and then send the response too.
        res.status(403).json("Token is not valid!"); 
      } else {
         req.user = user;
         next();
      }
    });
Related