Search code examples
expresssessionredissession-cookiesexpress-session

Session ID changes although resave has been set to true (the client doesn't take the new expiration date into account)


I'm using NodeJS an express session handling with Redis. Here is the interesting part:

let session = require('express-session')
let cookieParser = require('cookie-parser')
let Redis = require('ioredis');
let clientRedis = new Redis();
let RedisStore = require('connect-redis')(session);

const SESSIONSECRET = require(config.get('app.secretsession')).secret;
app.use(cookieParser(SESSIONSECRET));

const sessionMiddleware = session({
  store: new RedisStore({
    client: clientRedis,
  }),
  secret: SESSIONSECRET,
  resave: true,
  saveUninitialized: true,
  cookie: {
    maxAge: 30000,
    secure: false,
    httpOnly: true,
    domain: config.get('app.domainecookie')
   }
});

app.use(sessionMiddleware);

I'm making periodically calls to my server, and I see the "expires" parameter of my cookie updates correctly, pushing the 30000 limit further. But, for some reason, the session is destroyed and I get another session ID, again for 30000.

Here is what I use to check my session ID:

app.use((req, res, next) => {
  console.log(`CURRENT SESSION: ${req.session.id}`);
})

When I check in my browser, I see that even if the cookie expiration date changes on the server, it doesn't change in the client (browser). Is there a way to update the expiration date client-side?

I thought I could resend the cookie like this:

app.use((req, res, next) => {
  console.log(`CURRENT SESSION: ${req.session.id}`);
  res.cookie('connect.sid', req.sessionID, req.session.cookie);
})

But it keeps changing the cookie to another one, sometimes with the value of a correct sessionID, sometimes with 's:' followed by a value of another cookie.

I thought I could send the 'connect.sid' cookie from my client to the server to update it, but as it's a signed cookie I would have to use the same secret client-side and that is clearly not possible.

What am I doing wrong here? I thought setting "resave" to true wouldn't destroy the session.


Solution

  • Waw, that was not as easy as it should be. I finally found what to do: the problem was I had to sign the cookie with the same secret as I initialized it. For that, I had to install the cookie-signature package.

    npm i --save cookie-signature
    

    I create a signature function like this:

    const signature = require('cookie-signature').sign;
    

    Then, in my middleware app.use function, I simply had to write these lines (look at the s: which is added for some reason...):

    const signedSessionId = signature(req.sessionID, SESSIONSECRET);
    res.cookie('connect.sid', `s:${signedSessionId}`, req.session.cookie);
    

    Like this, the expiration date of the cookie client-side is pushed further, like it is in the server-side.

    Note: it's very strange that the connect.sid cookie doesn't update automatically client-side even though it has been updated server-side. I don't see the point of using resave: true if the information is not passed to the client. If I misread the documentation and there is actually a native way to do it, I'd be glad to know the way.