4

I am trying to make Express session work with Next.js, and have successfully done so on the client side, but I am having trouble with API calls made from inside getInitialProps.

Note: I am using isomorphic-unfetch to make API calls. My Next.js installation runs on localhost:3000, my Express server on localhost:5000.

Here is an example of a client side API call (outside of getInitialProps):

componentDidMount() {
  fetch('/path/to/endpoint', {
    method: 'GET',
    credentials: 'include',
  }).then((res) => console.log(res));
}

I'm logging res here because I wanted to see the headers. Turns out this request has an empty headers object. If i resolve the promise I get the data I requested though. The session ID from this call stays consistent on the server even if I refresh the page. Everything is working as expected here.

Here is an example of an API call inside getInitialProps:

static async getInitialProps(ctx) {
  fetch('/path/to/endpoint', {
    method: 'GET',
    credentials: 'include',
  }).then((res) => console.log(res.headers));
}

Again, logging to see the headers. This response has headers, they look like this:

Headers {
_headers:
{ 'x-powered-by': [ 'Express' ],
'access-control-allow-origin': [ 'http://localhost:3000' ],
vary: [ 'Origin, Accept-Encoding' ],
'access-control-allow-credentials': [ 'true' ],
'x-frame-options': [ 'SAMEORIGIN' ],
'x-xss-protection': [ '1; mode=block' ],
'set-cookie'['YgJGcZPBgbE_nEqqLZpw0ba0pyaf2eNS','connect.sid=s%3AYgJGcZPBgbE_nEqqLZpw0ba0pyaf2eNS.Oye%2F7%2BsyXrrLJwphEJ3nq3yMkBhM3%2Fm4PCl9KIV%2FTzA; Path=/; Expires=Sun, 05 Aug 2018 15:56:52 GMT;     HttpOnly' ],
'content-type': [ 'application/json; charset=utf-8' ],
'content-length': [ '246' ],
etag: [ 'W/"f6-82FKQ+ERtkxLiKa8hEIeY4kgGgE"' ],
date: [ 'Sun, 22 Jul 2018 15:56:52 GMT' ],
connection: [ 'close' ] } }

As you can see there is connect.sid (express session ID) in my set-cookie header, but the problem is that the connect.sid cookie changes whenever I refresh the page and does not match the session ID of client side API calls (which stays the same even after refreshing the page).

My session object on the Express server looks like this:

app.use(
  session({
  resave: false,
  name: 'connect.sid',
  saveUninitialized: false,
  secret: SESSION_SECRET,
  unset: 'destroy',
  cookie: {
    maxAge: 3600000 * 24 * 14,
    secure: false,
  },
  store: new MongoStore({
    url: mongoUrl,
    autoReconnect: true,
  }),
})

);

If anyone has an idea how I can make API calls from inside getInitialProps work with express session I'd appreciate the input! Thank you in advance.

Robert
  • 171
  • 1
  • 8

1 Answers1

13

I found the solution. Instead of using credentials: 'include' I had to send the session cookie in the request header. Here's a working request inside getInitialProps.

static async getInitialProps(ctx) {
      const res = await fetch('path/to/endpoint', {
        headers: {
          cookie: ctx.req.headers.cookie,
        },
      });
      const user = await res.json();

      return { user };
    }
Robert
  • 171
  • 1
  • 8
  • 1
    Thank you!! Why isn't the cookie sent by default?! – Barrard Jun 08 '19 at 09:13
  • As far as I understand CORS is a contract between a server and the browser. Since getInitialProps only runs during server side rendering and not during client side rendering, it doesn't know about CORS and therefore can't interprete `credentials: 'include'`. Maybe looking at the documentation will help you understand it better: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials As for why the cookie is not sent by default, I guess the answer simply is that Next.js has no implementation for sending cookies by default. – Robert Jun 10 '19 at 08:35
  • "getInitialProps is also going to run on the client side. If you have code that you only want to run on the server, you can check process.browser, it will be true only on the client." - copied from a chat in spectrum nextjs community – dparkar Sep 17 '19 at 17:29
  • this sounds very similar to my problem : https://stackoverflow.com/questions/57979227/nextjs-expressjs-azure-web-app-two-factor-authentication-with-express-fs – dparkar Sep 17 '19 at 17:30
  • 1
    For the record, this doesn't play nice with axios. Once I switched to isomorphic-fetch, it started working. – remjx Feb 08 '20 at 02:10