Cookie not set with express-session in production

Viewed 7970

My app is divided between Client and Server. Client is a frontend side Nextjs app hosted on Now.sh, Server is its backend created with Express and hosted on Heroku, so the domains are client-app.now.sh and server-app.herokuapp.com .


Authentication

Authentication system is based on cookies and I'm using express-session to achieve it. This is my express-session configuration

app.use(
  session({
    store:
      process.env.NODE_ENV === "production"
        ? new RedisStore({
            url: process.env.REDIS_URL
          })
        : new RedisStore({
            host: "localhost",
            port: 6379,
            client
          }),
    name: "sessionID",
    resave: false,
    saveUninitialized: false,
    secret: keys.SESSION,
    unset: "destroy",
    cookie: {
      domain:
        process.env.NODE_ENV === "production"
          ? ".client-app.now.sh"
          : "localhost",
      secure: process.env.NODE_ENV === "production",
      httpOnly: true,
      maxAge: 7 * 24 * 60 * 60 * 1000
    }
  })
);

Cors is set with the "cors" package:

app.use(
  cors({
    origin:
      process.env.NODE_ENV === "production"
        ? process.env.CLIENT_URL
        : "http://localhost:3000",
    credentials: true
  })
);

Client is configured with Apollo and "credentials" in HttpLink is set to "include".

The problem is that cookie with session ID is correctly set in development, but not in production. Could this be related to the fact that I'm hosting client and server on different domains?

2 Answers

I had my production node server behind a reverse proxy. This causes node to not trust the proxy and thus not set cookies.

I had to enable trusting the first proxy when in production.

app.set('trust proxy', 1) // trust first proxy

More info check out express-session's docs on the topic.

After a lot of time trying to solve this, I just found the solution:

So I had,

app.use(session({
  secret: secret,
  saveUninitialized: false,
  resave: false,
  cookie: { 
    domain: clientDomain,
    secure: true
}
}));

I removed all the cookie object and this solved my issue:

app.use(session({
  secret: secret,
  saveUninitialized: false,
  resave: false
}));

Browsers seems don't need help to get the cookies.

Related