Search code examples
reactjsnode.jsmongodbcookiescors

cookie is Not getting send in request headers after deployment to Vercel


I am building a MERN blog app. Initially it was running fine before deploying to vercel. The server was hosted on http://localhost:3000 and the client react part was hosted on http://localhost:8000. The server file was deployed on vercel. Other routes are working fine , but the routes which requires cookies (token) are not working. When i see in the request headers, the cookie is not being send. But when i do it before deployment on vercel , it sends the cookies as well to the backend. Why is the error?

The vercel url for backend is : https://blog-app-server-red.vercel.app/

Code for frontend (react) :

const getProfilePic = async ()=>{
     try {
      const response = await fetch('https://blog-app-server-red.vercel.app/user/'+userId , {
        credentials : 'include',
        headers: {
          "Content-Type": "application/json",
          "Access-Control-Allow-Credentials": true,
        }
      })

Code for backend (express , mongo) :

app.get('/user/:id' , async (req, res)=>{
    try {
                const {token} = req.cookies;
                const {id} = req.params;
                if(token){
                    jwt.verify(token , process.env.JWT_KEY , {} , async (err , info)=>{
                        if(err){
                            throw "Wrong Token ! Access Denied"
                        }
                        const user = await User.findById(id).select('-password');
                        res.status(200).json(user);

                    });
                }
                else{
                    res.status(400).json({error : "Unauthorized !!!"})
                }
            } catch (error) {
                res.status(400).json({error});
            }
})

CORS middleware (backend) :

app.use(cors({credentials : true , origin : 'http://localhost:3000'}));

When the same is done for http://localhost:8000 (backend api) , it works fine and the cookie is also getting send. WHy is it?


Solution

  • This issue seems due to CORS and cookie policies when your backend is deployed on Vercel.

    Try these configuration to make sure cookies are sent correctly on server,

    const allowedOrigins = ['http://localhost:8000', 'https://your-frontend-domain.vercel.app'];
    
        app.use(cors({
            credentials: true,
            origin: (origin, callback) => {
                if (allowedOrigins.includes(origin) || !origin) {
                    callback(null, true);
                } else {
                    callback(new Error('Not allowed by CORS'));
                }
            }
        }));
    

    Make sure the cookies set by backend server endpoint have the appropriate attributes to be sent in cross-origin requests. You need to set the SameSite attribute to None and ensure the Secure attribute is set to true for secure contexts (HTTPS)

    res.cookie('token', token, {
        httpOnly: true,
        secure: true,
        sameSite: 'None'
    });
    
    

    On your frontend code all looks good, adding try-catch for error handling would be good.

    const getProfilePic = async () => {
        try {
            const response = await fetch('https://blog-app-server-red.vercel.app/user/' + userId, {
                credentials: 'include',
                headers: {
                    "Content-Type": "application/json",
                    "Access-Control-Allow-Credentials": true,
                }
            });
    
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
    
            const data = await response.json();
            return data;
        } catch (error) {
            console.error('There was a problem with your fetch operation:', error);
        }
    };
    
    

    Only if you are using sessions, make sure the session configuration allows cross-origin cookies,

    app.use(session({
        secret: 'your-secret-key',
        resave: false,
        saveUninitialized: true,
        cookie: {
            secure: true, // Ensure this is true if using HTTPS
            sameSite: 'None'
        }
    }));
    
    

    your frontend and backend are both should served over HTTPS when in production. Browsers block cookies that are flagged as Secure when sent over non-secure connections.

    Use the browser’s developer tools to verify that the cookie is being set and sent correctly. Check under Application > Cookies to ensure the token is stored correctly and under Network > Headers to see if the cookie is included in the request.