6

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?

The_Wolf
  • 155
  • 4
  • 11
  • I have the same issue. I host my App on Heroku + my NodeJS Server on Heroku. On localhost cookie was set fine but since I host it on Heroku it wont set cookies anymore. I recognized that the req.session.cookie is set in NodeJS but no cookie is set on clients browser – Jonathan Dec 19 '18 at 07:21
  • 1
    @Jonathan my problem was identical to this: https://github.com/expressjs/session/issues/600 . During this days I tried pushing frontend on Heroku too, but it didn't work, so my last attempt was to use a custom Nextjs server as the main server also for backend and without any additional configuration it worked! TL;DR: I had client and server divided with their own servers. I used client server as the backend too and hosted it on Heroku (so with only one domain) and now cookies works. Different subdomains gave me the problem. – The_Wolf Dec 19 '18 at 10:52
  • 1
    BTW i am happy to say this: I SOLVED THIS ISSUE! Maybe it sounds weird but just remove the `domain` of your cookie. So just dont set a domain for your cookie! This worked for me :) – Jonathan Dec 19 '18 at 12:11

2 Answers2

3

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.

DariusV
  • 1,739
  • 11
  • 19
  • 1
    This is wrong. Omitting "cookie" from the express-session options simply means that express-session will send it's session cookie with default values. – Marius Lian Aug 09 '20 at 08:44
  • I don't need to send any special cookies to the client so this solves the issues for me. – DariusV Aug 09 '20 at 20:03
3

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.

Sir.Nathan Stassen
  • 1,570
  • 2
  • 17
  • 24
  • This worked for me. Was running Nest.js on Nginx on my laptop but the production server was running Apache so had to set this. – OzzyTheGiant Apr 19 '21 at 04:36
  • This answer worked for me as well. I was sending secure httpOnly cookie, it worked fine on local (cookie was sent, seen in postman), but it wasn't being sent when app was live on heroku. After adding this line, it worked correctly. – ciphrd Apr 19 '21 at 12:21