DevFlow

DevOverflow

Search
Menu
DevFlow

DevOverflow

Home menu icon

Home

Community menu icon

Community

Collections menu icon

Collections

Find Jobs menu icon

Find Jobs

Tags menu icon

Tags

Ask a question menu icon

Ask a question

    Menu

    Top Questions

    How to center a div?

    chevron

    How to do code parsing with React.js and NextJS?

    chevron

    How to get better at Nextjs?

    chevron

    Postgres: upgrade a user to be a superuser? ?

    chevron

    This is another test question

    chevron

    Popular Tags

    nextjs

    6

    React

    4

    next.js

    3

    reactjs

    3

    css

    3

    Profile

    Juan Cruz Cáceres

    upvote

    0

    downvote

    0

    star

    can't get cookies to work. Node/React/Vercel/Render

    clock icon

    Asked 10 months ago

    message

    0 Answers

    eye

    1 Views

    0

    I did not write the backend, and do not have backend experience. It was 2 man project and now I am trying to gain that experience by deploying it.
    I have backend deployed on Render, frontend on Vercel.
    Everything worked in development, and in preview as well. It was only after deploying, that the cookie based issues appeared, meaning to test the code I have to keep redeploying as they won't appear in testing.

    const path = require('path');
    
    const      express = require('express');
    const   bodyParser = require('body-parser');
    const     mongoose = require('mongoose');
    const      session = require('express-session');
    const MongoDBStore = require('connect-mongodb-session')(session);
    const       socket = require('socket.io');
    const       multer = require('multer');
    const         cors = require('cors');
    require('dotenv').config();
    
    const User = require('./models/user');
    
    const MONGODB_URI = process.env.MONGO_KEY;
    const    app = express();
    const   http = require('http');
    const server = http.createServer(app);
    const     io = socket(server);
    
    let users = [];
    
    const addUser = (userId, socketId) => {
      !users.some((user) => user.userId === userId) && users.push({ userId, socketId });
    };
    
    const removeUser = (socketId) => {
      users = users.filter((user) => user.socketId !== socketId);
    };
    
    const getUser = (userId) => {
      return users.find((user) => user.userId === userId);
    };
    
    io.on('connection', (socket) => {
      // when connect
      console.log('a user connected.');
    
      // take userId and socketId from user
      socket.on('addUser', (userId) => {
        addUser(userId, socket.id);
        io.emit('getUsers', users);
      });
    
      // send and get message
      socket.on('sendMessage', ({ senderId, receiverId, text }) => {
        const user = getUser(receiverId);
        io.to(user.socketId).emit('getMessage', {
          senderId,
          text,
        });
      });
    
      // when disconnect
      socket.on('disconnect', () => {
        console.log('a user disconnected!');
        removeUser(socket.id);
        io.emit('getUsers', users);
      });
    });
    
    const store = new MongoDBStore({
             uri: MONGODB_URI,
      collection: 'sessions',
    });
    
    const storage = multer.diskStorage({
      destination: (req, file, cb) => {
        cb(null, 'images');
      },
      filename: (req, file, cb) => {
        cb(null, new Date().toISOString().replace(/:/g, '-') + '-' + file.originalname);
      },
    });
    
    const fileFilter = (req, file, cb) => {
      if (
        file.mimetype === 'image/png' ||
        file.mimetype === 'image/jpg' ||
        file.mimetype === 'image/jpeg'
      ) {
        cb(null, true);
      } else {
        cb(null, false);
      }
    };
    
    app.set('views', 'views');
    app.set('view engine', 'ejs');
    
    const  marketRoutes = require('./routes/market');
    const   adminRoutes = require('./routes/admin');
    const    authRoutes = require('./routes/auth');
    const messageRoutes = require('./routes/message');
    const    chatRoutes = require('./routes/chat');
    const          user = require('./models/user');
    
    app.use(
      cors({
             origin: process.env.CLIENT_URL, // configured to accept credentials from front end for session cookies to work
        credentials: true,
      })
    );
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(multer({ storage: storage, fileFilter: fileFilter }).single('image'));
    app.use(express.static(path.join(__dirname, '/public')));
    app.use('/images', express.static(path.join(__dirname, 'images')));
    app.use(
      session({
                   secret: 'my secret',
                   resave: false,
        saveUninitialized: false,
                    store: store,
                   cookie: {
                         maxAge: 30 * 24 * 60 * 60 * 1000,
                       httpOnly: true,   
                         secure: true,  
                       sameSite: 'None', 
                  },
      })
    );
    
    app.use((req, res, next) => {
      res.locals.isAuthenticated = req.session.isLoggedIn;
      next();
    });
    
    app.use((req, res, next) => {
      if (!req.session.user) {
        return next();
      }
      User.findById(req.session.user._id)
        .then((user) => {
          if (!user) {
            return next();
          }
          req.user = user;
          next();
        })
        .catch((err) => {
          console.log(err);
        });
    });
    
    app.use(marketRoutes);
    app.use(adminRoutes);
    app.use(authRoutes);
    app.use(messageRoutes);
    app.use(chatRoutes);
    
    mongoose
      .connect(MONGODB_URI)
      .then((result) => {
        server.listen(3000);
        console.log('connected!');
      })
      .catch((err) => {
        console.log(err);
      });
    

    So after going round in circles with several AIs, they keep repeating the same thing, to add these lines that I did not originally have:

                       httpOnly: true,   
                         secure: true,  
                       sameSite: 'None', 
    

    This hasn't worked. Without these lines, the app did have full functionality only in Firefox browser. Any other browser I tested it on, you can see the DB data, you can signup/login (POST requests), but you cannot perform any other request, because the controller will check for a req.session.user in pretty much every controller. This relies on cookies to work correctly. The client side will use some hooks to make requests which will call this function

    export interface Fetch {
      params: string;
      method: 'GET' | 'POST' | 'PUT' | 'DELETE';
       data?: object;
    }
    
    export const fetchData = async ({ params, method, data }: Fetch) => {
      const isFormData = data instanceof FormData;
      const body = data ? (isFormData ? data : JSON.stringify(data)) : null;
    
      const response = await fetch(import.meta.env.VITE_SERVER_URL + params, {
        method,
        headers: isFormData ? undefined : { 'Content-Type': 'application/json' },
        credentials: 'include', // send cookies to backend
        body,
      });
    
      const resData = await response.json();
    
      if (!response.ok) {
        throw resData;
      }
    
      return resData;
    };
    

    The Cors is set to receive credentials. Credentials set to true on Client side. Everything works in Dev/Preview and Firefox with the App code just like this:

    app.use(
      session({
                   secret: 'my secret',
                   resave: false,
        saveUninitialized: false,
                    store: store,
                   cookie: {
                       maxAge: 30 * 24 * 60 * 60 * 1000, 
                  },
      })
    );
    

    But the cookies will not work in any non Firefox browser. Then adding the extra cookie config prevents it from working in any environment at all.

    I have tried amending the cookie config and redeploying but it only made it less functional. I would have thought the set up is correct but I am not able to receive any further help on this. Right now I could deploy it without the cookie config and just leave a note that this only has full functionality in Firefox.

    nodejs
    vercel
    cors

    Write your answer here

    0 Answers