node.jsauthenticationexpress-session

`req.session.user` does not save


After user logs in, some information about the user is saved in req.session.user, like his id,username and role

But verifyUser middleware always returns status 401 because it thinks that req.session.user is undefined

Login route

router.post("/",... , async (req,res) => {
    ...
    // Authenticate the user
    req.session.user= {
      id: user._id.toString(),
      username: username,
      role: user.role,
    };
    console.log("User logged in and session.user is");
    console.log(req.session.user); // NOTE: This logs correctly
    req.session.save();
    res.status(200).json({
      message: "User logged in successfully.",
      info: { id: user._id, username: username, role: user.role },
    });
})

verifyUser middleware

const verifyUser = async (req, res, next) => {
  try {
    console.log(req.session.id); // NOTE: Always different
    console.log(req.session.user); // NOTE: Always undefined
    if (!req.session.user) {
      return res.status(401).json({ message: "Log in again." });
    }
    req.userId = req.session.user.id;
    req.userRole = req.session.user.role;
    next();
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json({ message: "Error in the server"});
  }
};
module.exports = verifyUser;

Here is the express-session and how it's defined

const session = require("express-session");
const cookieParser = require("cookie-parser");
app.use(
  session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: { maxAge: 1000 * 60 * 60 * 24 },
    secure: !process.env.UNSECURE_COOKIES, // Use secure cookies in production
  })
);
app.use(cookieParser());
// ...

And these are corsOptions also:

// CORS middleware function to check the origin against the allowed list
const corsOptions = {
  credentials: true,
  origin: function (origin, callback) {
    if (allowedOrigins.indexOf(origin) !== -1 || !origin) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  optionsSuccessStatus: 200, // For legacy browser support
};

This is also how user logs in, it just send fetch request and then redirects

   const response = await fetch(`${url}/login`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });

And this is how user is authenticated on routes that need authentication:

window.getUsers = async function () {
  const reqOptions = {
    method: "GET",
    credentials: "include",
  };
  try {
    const data = await fetch(`${url}/users/all`, reqOptions);
    const result = await data.json();
    return result;
  } catch (error) {
    console.error(error);
    alert("Error connecting.");
  }
};

PR: https://github.com/Cro-Cube-Comp/Cubing-competition/pull/29

Github branch: https://github.com/Cro-Cube-Comp/Cubing-competition/tree/session-auth

I added console.log(req.session.user) into the /login route after user is authenticated, it logged correctly.

I also added that log in verifyUser middleware, and it always logged undefined

I added console.log(req.session.id) in verifyUser middleware and it logged something different every time

Server is hosted on http://localhost:3000 and my website is on http://localhost:2500


Solution

  • The error was in verifyUser middleware. It is not supposed to be async.