Cookies aren't stored in the browser after deployment

i am building a full stack web app using expressJS for the backend and NextJS for the frontend. I have built the /login endpoint and it’s working fine locally. However, it didn’t work after I deployed it on vercel.

The problem is that I send a cookie from the backend and it’s working fine but it’s not stored in the browser after deployment. It’s working fine on localhost.

export const login = async (req, res) => {
    try {
        const { username, password } = req.body;

        // Check user exists
        const user = await prisma.user.findUnique({ where: { username } });
        if (!user) return res.status(401).json({ message: "Invalid credentials" });

        // Check correct password
        const isValidPassword = await bcrypt.compare(password, user.password);
        if (!isValidPassword) return res.status(401).json({ message: "Invalid credentials" });

        // Generate a cookie tooken
        const age = 1000 * 60 * 60 * 24 * 7; // 7 days

        const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: age });
        const { password: password_, ...userInfo } = user;
        const isProduction = process.env.NODE_ENV === "production";

        return res.cookie(
            "token",
            token, {
            httpOnly: true,
            secure: isProduction,
            sameSite: isProduction ? "none" : "lax",
            path: "/",
            // domain: isProduction ? '.vercel.app' : ".localhost",
            partitioned: isProduction,
            maxAge: age,
        }
        ).json({ message: "Login successful", data: userInfo });

    } catch (err) {
        console.log(err)
        return res.status(500).json({ message: "Failed to login" })
    }
}
// api/index.js
 import express from 'express';
import dotenv from "dotenv";
import authRoutes from "../routes/auth.route.js";
import cookieParser from 'cookie-parser';
import cors from "cors";
const port = process.env.PORT || 4000;
dotenv.config()

const app = express();
app.set('trust proxy', 1);
app.use(cors({
    origin: process.env.CLIENT_URL,
    credentials: true,
}))
app.use(express.json());
app.use(cookieParser());
app.use("/api/auth", authRoutes);

app.get("/", (req, res) => {
    return res.send("It works");
})
app.use((_err, _req, res, _next) => {
    res.status(500).json({
        status: 'Failed',
        message: 'Something went wrong',
    });
});


app.listen(port, () => console.log(`server running at ${port}`));

export default app;
// axios config
import axios from "axios";
export const apiRequest = axios.create({
    baseURL: `${process.env.NEXT_PUBLIC_API_URL}/api`,
    withCredentials: true,
})
// frontened
const res = await apiRequest.post("/auth/login", {
        username,
        password,
 });

If you’re having trouble deploying an Express app, this guide can help.

You can also ask v0 for suggestions tailored to your own project setup.

Also it’s sending the cookies correctly from the backend

Hi @rawda-yasser, welcome to the Vercel Community!

I think this issue is most likely to be related to the allowed domain. Can you share the domain where is the express backend hosted and where is the Next.js frontend hosted?

1 Like

This is the backend
https://rawdaymohamed-my-estate-backend.vercel.app/

This is the frontend

@anshumanb is that what you mean?

@anshumanb Can you show what you mean by allowed domains?
Everything is working correctly in the deployment except the cookie storage in the browser. The backend is connected correctly to the frontend

app.use(cors({
    origin: process.env.CLIENT_URL,
    credentials: true,
}))

Hi @rawda-yasser, I think in the domain isn’t set properly here. As per MDN docs:

Contrary to earlier specifications, leading dots in domain names (.example.com ) are ignored.

So, you should set the domain to rawdaymohamed-my-estate.vercel.app exactly.

Can you give this a try?

@anshumanb I tried it but it still doesn’t store cookies in the frontend

export const login = async (req, res) => {
    try {
        const { username, password } = req.body;

        // Check user exists
        const user = await prisma.user.findUnique({ where: { username } });
        if (!user) return res.status(401).json({ message: "Invalid credentials" });

        // Check correct password
        const isValidPassword = await bcrypt.compare(password, user.password);
        if (!isValidPassword) return res.status(401).json({ message: "Invalid credentials" });

        // Generate a cookie tooken
        const age = 1000 * 60 * 60 * 24 * 7; // 7 days

        const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: age });
        const { password: password_, ...userInfo } = user;
        const isProduction = process.env.NODE_ENV === "production";

        return res.cookie(
            "token",
            token, {
            httpOnly: true,
            secure: isProduction,
            sameSite: isProduction ? "none" : "lax",
            path: "/",
            domain: isProduction ? 'rawdaymohamed-my-estate.vercel.app' : "localhost:4000",
            maxAge: age,
        }
        ).json({ message: "Login successful", data: userInfo });

    } catch (err) {
        console.log(err)
        return res.status(500).json({ message: "Failed to login" })
    }
}

Oh I see. Can you confirm if isProduction is true in the deployed version of your app? Also, can you share a response from the deployed app so we can see what the set-cookie header contains.

Yes the NODE_ENV is set to production
These are the responses

Hi @rawda-yasser, can you try the same in another browser? You are using Firefox which might have default settings to ignore cookies.

Related post: firefox will not accept cookies even though cookies setting is standard. | Firefox Support Forum | Mozilla Support

@anshumanb it saves cookies on chrome but once I refresh the browser the cookies are gone

Hi @rawda-yasser, I’d recommend reading up on the latest Cookies features and changes. There might be some changes in how browsers now treat the SameSite and Domain settings.

This isn’t a Vercel issue as such, but we can continue to debug this together. Feel free to share your findings.

Sure, can you provide me with some resources? I’d appreciate it

Hi @rawda-yasser, sure. I’d say for all web related queries MDN is the most reliable source.

I recommend you to give these docs a read:

I will check them and try again. Thanks

1 Like