Search code examples
javascriptnode.jscookiesjwtmern

Error while generating token and passing it between frontend and backend in MERN stack using jsonwebtoken


ERROR:

TypeError: Cannot read property 'jwtoken' of undefined

Overview: A token is generated using JSONwebtoken whenever a user logs into his account. This token is then passed to the backend. The user can see the 'about page' only after the token stored in cookies is verified against the token stored in the database (token is generated and stored in the database when the user logs in).

  • There are two pages in frontend login and about

  • authenticate.js file throws an error at line 1

  • the code is running on localhost: Frontend(3000), backend(5000)

CODE (backend files):

authenticate.js (middleware)

const authenticate = async (req, res, next) => {
  try {
    const token = req.cookies.jwtoken;  //this line throws an error
...//more code

auth.js: (router file)

router.post("/signin", async (req, res) => {
  let token;
  const { email, password } = req.body;

  if (!email || !password) {
    return res.status(422).json({ error: "invalid creds" });
  }

  try {
    const userLogin = await User.findOne({ email: email });

    if (!userLogin) {
      return res.status(422).json({ error: "invalid email" });
    } else {
      token = await userLogin.generateAuthToken();

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

      const isMatch = await bcrypt.compare(password, userLogin.password);
      if (!isMatch) {
        return res.status(422).json({ error: "invalid password" });
      }
      res.status(201).json({ msg: "login successful" });
    }
  } catch (error) {
    console.log(error);
  }
});

router.get("/about", authenticate, (req, res) => { //authenticate is middleware
  res.send(req.rootUser);
});

userSchema.js-> token is generated , database model schema

  try {
    let tokenVal = jwt.sign({ _id: this._id }, process.env.SECRET_KEY);
    this.tokens = this.tokens.concat({ token: tokenVal });
    await this.save();
    return tokenVal;
  } catch (err) {
    console.log(err);
  }
};

frontend files:

about.js

const About = () => {
  const history = useHistory();

  const callAboutPage = async () => {
    try {
      const res = await fetch("/about", {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
          Accept: "application/json", 
        },
        credentials: "include", //i.e send cookies
      });

      const data = await res.json();
      console.log(data);

      if (!res.status === 200) {
        const error = new Error(res.error);
        console.log(error);
        throw error;
      }
    } catch (err) {
      console.log(err);
      history.push("/login");
    }
  };

  useEffect(() => {
    callAboutPage();
  });

login.js

onst Login = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const history = useHistory();

  const loginUser = async (e) => {
    e.preventDefault();

    const res = await fetch("/signin", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },

      body: JSON.stringify({
        email,
        password,
      }),
    });
    const data = res.json();
    if (!data || res.status === 422) {
      window.alert("Invalid creds");
    } else {
      window.alert("LOGIN successful");
      history.push("/");
    }
  };
  • complete error log
TypeError: Cannot read property 'jwtoken' of undefined
    at authenticate (F:\projects\mern\basicMernProject\server\middleware\authenticate.js:6:31)
    at Layer.handle [as handle_request] (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\layer.js:95:5)
    at next (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\route.js:137:13)        
    at Route.dispatch (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\layer.js:95:5)
    at F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:335:12)
    at next (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:275:10)        
    at Function.handle (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:174:3)
    at router (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:47:12)       
    at Layer.handle [as handle_request] (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:317:13) 
    at F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:335:12)
    at next (F:\projects\mern\basicMernProject\server\node_modules\express\lib\router\index.js:275:10)        
    at jsonParser (F:\projects\mern\basicMernProject\server\node_modules\body-parser\lib\types\json.js:110:7) 
  • The token is always generated and stored in the database (verified) and is also visible in the cookies section in the frontend

Solution

  • Looks like you don't use any cookie related middlewares. Express doesn't parse request cookie headers by default. That's why your req object doesn't have cookies property. To make it work you should consider adding a cookie-parser middleware when initializing your express application:

    // server.js?
    const express = require('express')
    const cookieParser = require('cookie-parser')
    
    const server = express()
    server.use(cookieParser())
    

    This middleware creates and populates cookies property on the req object.