reactjsmernexpress-sessionpassport-localrender.com

passport-local's deserializeUser() is not called during deployment. Works fine in development


(Yes, I know class components are outdated, updating to functional/hooks after successful deployment)

I have implemented a MERN (MongoDB, Express, React, and Node.js) application with authentication using Passport's local strategy and ES6.

Expected: When the user logs in, they send a request to the "/auth/login" route, which is authenticated using the passport.authenticate() method. If the authentication is successful, the server sends a "success" response back to the client.

Once the client receives the "success" response, the App.js component's componentDidMount() method is called. In this method, the client sends a request to the "/auth/test" route to check if the user is authenticated using req.isAuthenticated().

If the user is authenticated, the server sends back the user object, which is then stringified and stored in the client's local storage to indicate that the user is logged in.

Development Mode: For development, I am having the client on one port and the API on another. Everything works fine.

Currently: After deployment, I am hosting both the client and API through Render.com.

Current Flow:

Notes on CORS:

Problem: req.isAuthenticated() returns false because req is undefined.

What I've witnessed (through console logs):

Thank you

Client

/auth/login

    const url = baseURL + "/auth/login?username=" + id + "&password=" + pw;
    const res = await fetch(url, {
      method: "POST",
      credentials: "include",
    });

/auth/test

     fetch(baseURL + "/auth/test", {
        credentials: "include",
      })

API

/auth/login Route

authRoute.post("/auth/login",passport.authenticate("local"),
  (req, res) => {
    res.status(200).send("Login successful");
  },

/auth/test Route

authRoute.get("/auth/test", (req, res) => {
  const isAuth = req.isAuthenticated(); // PROBLEM: Returns false because req is undefined
// etc.

passportConfig

  app
    .use(
      session({
        secret: process.env.SESSION_SECRET,
        resave: false,
        saveUninitialized: true,
        cookie: {
          secure: process.env.NODE_ENV === "development" ? false : true,
          httpOnly: process.env.NODE_ENV === "development" ? false : true,
          sameSite: process.env.NODE_ENV === "development" ? "" : "none", // Set if using CORS
          domain: process.env.NODE_ENV === "development" ? "" : ".onrender.com",
          path: "/",
          maxAge: 1000 * 60 * 5,
        }, // 5 minutes
      })
    )

    .use(passport.initialize())
    .use(passport.session());

Thanks in advance!


Solution

  • One thing that looks suspect in your configuration is this line, specifically the . preceding your domain:

    domain: process.env.NODE_ENV === "development" ? "" : ".onrender.com", line.

    I would drop that line entirely. You could also change it to just onrender.com.

    Express will also not set a cookie if the remote server is passing the request through a non-http intermediary. You can tell it to trust this proxy:

    if (process.env.NODE_ENV === 'production') {
      app.set('trust proxy', 1);
    }