Search code examples
expressredisexpress-session

Why is my express-session cookie being sent by API but not picked up in browser?


Cookie in express session is being sent by API but not picked up in browser. As a result a new session is being generated per API call

I am using express-session with Express backend and Vue frontend.

I have added an abbreviated version of the relevant code below:

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const session = require("express-session");
app.use(bodyParser.json());
const redis = require("ioredis");
const RedisStore = require("connect-redis").default;

//Configure redis client
const redisClient = redis.createClient({
  host: "127.0.0.1",
  port: 3002,
});

redisClient.on("error", function (err) {
  console.log("Could not establish a connection with redis. " + err);
});
redisClient.on("connect", function (err) {
  console.log("Connected to redis successfully");
});

app.use(
  session({
    secret: "megaultrasupersecret",
    saveUninitialized: true,
    store: new RedisStore({ client: redisClient }),
    resave: false,
    cookie: {
      sameSite: "none",
      secure: false,
      httpOnly: false,
    },
  })
);
app.use(cookieParser("megaultrasupersecret"));

app.use(
  cors({
    credentials: true,
    origin: ["http://localhost:5173"],
  })
);

I've researched various solutions such as this one. Many call for 'secure' to be set to false, which I already have.

I set debug mode of express-session when running my server and can see the cookie getting set initially -

express-session saving 3k7qKWwHSuWcz3eE--vQu-EENIvQ0WIk +1ms express-session set-cookie connect.sid=s%3A3k7qKWwHSuWcz3eE--vQu-EENIvQ0WIk.1i%2Fsaux3bkiyYiKzBVxaMJzqD%2FWbuaACkPwbW4Ql2aA; Path=/; SameSite=None +1ms

But then the next time my backend is called the logs read

express-session no SID sent, generating session +13ms

I also tried using mongo-store as well as Redis as the store.

Various solutions also call for 'saveUninitialized' to be false. I've tried it with both values with the same result.


Solution

  • So I could see Set-Cookie being returned in the response header, and ended up changing a whole lot of settings while troubleshooting. Below are the settings that finally worked for me. I think the pivotal change was using fetch on the FE instead of Axios, and taking 'samesite': 'None' out of the options for creating the cookie on the BE. If anybody has any additional feedback on this curious to know - not sure why this didn't work with Axios. https://developers.google.com/search/blog/2020/01/get-ready-for-new-samesitenone-secure BE portion:

    app.use(
      session({
        secret: "megaultrasupersecret",
        saveUninitialized: true,
        name: "appName",
        store: new RedisStore({ client: redisClient }),
        resave: false,
        cookie: {
          maxAge: 1800 * 24,
          secure: false,
          httpOnly: false,
          domain: "localhost",
          path: "/",
        },
      })
    );
    app.use(cookieParser("megaultrasupersecret"));
    
    app.use(
      cors({
        credentials: true,
        origin: ["http://localhost:5173"],
        exposedHeaders: ["set-cookie", "ajax_redirect"],
        preflightContinue: true,
        methods: ["GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS"],
        optionsSuccessStatus: 200,
      })
    );
    

    FE portion (example of updated API call to BE):

    getRecentlyCreatedForums() {
          const recentlyCreatedForums = await fetch('http://localhost:3001/forum', {
            method: 'GET',
            mode: 'cors',
            credentials: 'include'
          }).then((data) => data.json().then((data) => data))