Problem with cookie not save or sent to the frontend after a Mern deployment

34 views Asked by At

I'm using the MERN stack for an e-commerce site. I decided to use cookies with express-session to keep track of the currently logged-in user.

All my tests are passing fine locally, meaning that when the user logs in with the right credentials, they are redirected to the home page, from which I make another request to the back end to determine if they are indeed connected.

However, after deploying on Vercel and rendering, it no longer works. When the user logs in, the request I make to determine their status only returns a 403. It's been over 5 days that I've been trying to fix this, but nothing.

Also, I'm facing the same issue with OAuth requests such as Google and Facebook, but I prefer to start with this.

Thanks in advance for your responses.

The axios instance use to make requestyour text

The frontend url

/**
   * @desc authenticate a user with email and password
   * @route POST /auth/login
   * @access public
   * @param req
   * @param res
   * @returns
   */
  static async login(req: Request, res: Response) {
    const { email, password } = req.body;

    if (!email || !password) {
      return res.status(400).json({ status: 'error', message: 'All fields are required!' });
    }

    // check if the user exist
    const checkUser = await User.findOne({ email });
    // console.log('checkUser', checkUser);
    if (!checkUser) {
      return res.status(401).json({ message: 'Unauthorized ! ', status: 'error' });
    }

    // check if the password match
    const matchPassword = await bcrypt.compare(password, checkUser.password);
    // console.log('findUser', matchPassword, checkUser, password);

    // the password doesn't match
    if (!matchPassword) {
      return res.status(401).json({ message: 'Unauthorized', status: 'error' });
    }

    req.session.user = checkUser;
    req.session.userId = checkUser._id.toString();

    delete checkUser.password;
    console.log('user : ', req.session.id);

    return res.json({
      status: 'success',
      data: checkUser,
      message: 'successfully logged in',
    });
  }

The entry file of my nodejs backend

dotenv.config();

const PORT = process.env.PORT || 3500;
const secretKey = process.env.EXPRESS_SESSION_KEY as string;
const CLIENT_DOMAIN = process.env.CLIENT_DOMAIN as string;
const app = express();
const isProduction = process.env.NODE_ENV === 'production';

//

// other imports

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

AdminJS.registerAdapter({ Database, Resource });

const start = async () => {
  const mongoDB = await initializeDb();
  // await dbConnection();

  const admin = new AdminJS({
    ...options,
    databases: [mongoDB.db],
  });

  if (process.env.NODE_ENV === 'production') {
    await admin.initialize();
  } else {
    admin.watch();
  }

  const router = buildAuthenticatedRouter(
    admin,
    {
      cookiePassword: process.env.COOKIE_SECRET,
      cookieName: 'adminjs',
      provider,
    },
    null,
    {
      secret: process.env.COOKIE_SECRET,
      saveUninitialized: true,
      resave: true,
    }
  );
  // server files
  // app.use(express.static(path.join(__dirname, 'public', 'images')));

  app.use(admin.options.rootPath, router);
  configurePassport();

  // deleteAllDocuments(User);
  // logger middleware
  app.use(logger);
  // cookie-parser to manage secure cookie
  app.use(cookieParser());

  // cors
  app.use(cors(corsOptions));

  // session authentication configuration
  const sessionMiddleware = expresssession({
    secret: secretKey,
    resave: true,
    saveUninitialized: true,
    cookie: {
      maxAge: 1000 * 60 * 60 * 10,
      // TODO : change
      secure: !!isProduction,
      sameSite: isProduction ? 'none' : 'lax',
      domain: !isProduction ? 'localhost' : '.orender.com ',
      httpOnly: true,
    },
    name: 'oubuntu_cookie',
  });
  app.use(express.json());
  app.use(express.urlencoded({ extended: true }));
  app.use(sessionMiddleware);
  app.use(passport.initialize());
  app.use(passport.session());
  // static files
  app.use((req, res, next) => {
    res.header('Access-Control-Allow-Credentials', 'true');
    res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');

    if (req.method === 'OPTIONS') {
      res.sendStatus(200);
    } else {
      next();
    }
  });
  app.use('/', express.static(join(process.cwd(), 'src', 'public')));

  // root router
  app.use('/', rootRouter);

  // auth routes
  app.use('/api/auth', authRoute);

  // users Route
  app.use('/api/users', usersRoute);
  app.use('/api/products', productsRoute);
  app.use('/api/offers', offersRoute);
  app.use('/api/groups', groupsRoute);
  app.use('/api/categories', categoriesRoutes);

  // Catch-all routes
  app.all('/*', (req, res) => {
    res.status(404);

    if (req.accepts('html')) {
      // nothing
    } else if (req.accepts('json')) {
      res.json({ message: 'Not Found !' });
    } else {
      res.type('text').send('Not Found');
    }
  });

  // custom error handler
  app.use(errLogger);
  app.use(errorHandlerMiddleware);

  // listener
  mongoose.connection.once('open', () => {
    console.log('Connected to MongoDB');
  });
  app.listen(PORT, () => {
    console.log('Server is running on : ', `http://localhost:${PORT}`);
    console.log(`AdminJS started on http://localhost:${PORT}${admin.options.rootPath}`);
  });

  mongoose.connection.on('error', (err) => {
    console.log(`MongoDB connection error: ${err.message}`);
  });
};

start();

// authRoute

const authRoute = express.Router();
authRoute

  .post('/login', AuthenticationController.login)
  .get('/logout', AuthenticationController.logout)
  .get('/status', AuthenticationController.getUserStatus);

I tried many things like deploying frontend and backend to the same domain, configuring cookie domain and also sameSite options, but it still is just working perfectly in development mode, but not at all in production.

// here is the express-session configuration

    
  // cors
  app.use(cors(corsOptions));

  // session authentication configuration
  const sessionMiddleware = expresssession({
    secret: secretKey,
    resave: true,
    saveUninitialized: true,
    cookie: {
      maxAge: 1000 * 60 * 60 * 10,
      // TODO : change
      secure: isProduction,
      sameSite: isProduction ? 'none' : 'lax',
      domain: !isProduction ? 'localhost' : 'oubuntu-frontend-ori.onrender.com',
      httpOnly: true,
    },
    name: 'oubuntu_cookie',
  });
  app.use(express.json());
  app.use(express.urlencoded({ extended: true }));
  app.use(sessionMiddleware);
  app.use(passport.initialize());
  app.use(passport.session());
  // static files
  app.use((req, res, next) => {
    res.header('Access-Control-Allow-Credentials', 'true');
    res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');

    if (req.method === 'OPTIONS') {
      res.sendStatus(200);
    } else {
      next();
    }
  });
  app.use('/', express.static(join(process.cwd(), 'src', 'public')));

0

There are 0 answers