expressherokunext.jsredissession-cookies

Issue with session cookies not being sent in cross-origin responses with Express, Redis, and Next.js


I'm developing an application with an Express.js backend and a Next.js frontend. My backend uses Redis and connect-redis packages for session management, and my server is deployed on Heroku with the Heroku-Data for Redis add-on. I'm encountering an issue where session cookies are not being sent from the server to the frontend in a cross-origin context, despite configuring CORS headers to accept credentials. Here is an excerpt from my server-side (Express.js) configuration:

// app.js

...

// initialize Redis
async function initializeRedis() {
  
  const redisClient = redis.createClient({
    url: process.env.REDIS_TLS_URL, // url provided by Heroku-Data for Redis
    socket: {
      tls: true,
      rejectUnauthorized: false,
    },
  });

  redisClient.on("error", function (error) {
    console.error("Erreur de Redis :", error);
  });

  await redisClient.connect().catch(console.error);

  return redisClient;
}

// start app
async function startApp() {

  /* Redis
  -------------------------------------------------- */

  const redisClient = await initializeRedis();

  const redisStore = new RedisStore({ client: redisClient });

  /* Express Session
-------------------------------------------------- */

  const sessionConfig = {
    store: redisStore, 
    secret: process.env.EXPRESS_SESSION_SECRET_KEY,
    resave: false,
    saveUninitialized: false,
    cookie: {
      maxAge: 600000, // 10 minutes
      secure: process.env.NODE_ENV === "production",
      httpOnly: true,
      sameSite: process.env.NODE_ENV === "production" ? "None" : "Strict",
    },
  };

  /* CORS
-------------------------------------------------- */

  const cors = require("cors");

  const corsOptions = {
    origin: "https://www.my-site.app", 
    methods: ["GET", "POST"], 
    allowedHeaders: ["Content-Type", "Authorization"], 
    credentials: true,
  };

...
}

And here's how I'm making the requests on the client-side (Next.js):

// this request creates the session in the backend, storing the order id in the session cookie
const response = await fetch(
  `${process.env.NEXT_PUBLIC_SERVER_ENDPOINT}/validate-order`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(order),
    credentials: "include",
  }
);
// this request is supposed to receive the cookie from the session
 try {
      const response = await fetch(
        `${process.env.NEXT_PUBLIC_SERVER_ENDPOINT}/get-order-id`,
        {
          method: "GET",
          credentials: "include",
        }
      );

The session cookie is not received by the client when making requests to my API (with my front-end deployed to Vercel with https). No cookie in the response headers. I've checked and I'm sure that the issue is not related to CORS configurations, as the appropriate headers seem to be in place, and cross-origin requests are indeed allowed.

Has anyone encountered this issue or have any idea what might be going wrong ? Is there something specific to Heroku or Redis configuration that I might be missing ?

Thank you in advance for your help.

What I tried :

secure : false,
sameSite : « Strict »

but only when the request comes from http://localhost:3000 with the server running locally. I don’t receive the cookie when the server is running on Heroku with this configuration.

  const sessionConfig = {
    ...
    cookie: {
      ...
      domain: ".my-site.app", // do this only if your server and your front-end share the same domain, with your server on a subdomain like api.my-site.app
    },
  };

Solution

  • Issue solved by adding app.set("trust proxy", 1); to the server as mentioned here.

    Cloud services like Heroku often use reverse proxy so this line tells Express that the initial request was made over https even if it was transmitted over http after the proxy.