skip to Main Content

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.

2

Answers


  1. Chosen as BEST ANSWER

    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.


  2. If you want to handle your user’ session with a cookie, using express-session and connect-redis, you can normally follow this example

    const express=require('express');
    const app=express();
    const session = require('express-session')
    const Redis = require('ioredis');
    const clientRedis = new Redis();
    const RedisStore = require('connect-redis')(session);
    
    const SESSIONSECRET = "my-secret";
    const sessionMiddleware = session({
      store: new RedisStore({
        client: clientRedis,
      }),
      secret: SESSIONSECRET,
      saveUninitialized: true,
      resave:true,
      cookie: {
        maxAge: 60000,
        secure: false,
        httpOnly: true,
        domain:"localhost"
       }
    });
    app.listen(3000);
    app.use(sessionMiddleware);
    app.get("/",(req,res)=>{
        console.log(req.session.id)
        req.session.lastAccess=new Date().toISOString();
        res.json({"hello":"session"})
    })
    

    The node-session already parse the cookies, so you don’t need an other package for it. It also put everything in the response header automatically, so no need to set the res.cookie yourself.

    EDIT : I was a bit hasty, the express-session does not give you the cookies. It parse them but does not give you the cookies on the request object. You should still use cookie-parser package, if you are interest in other cookies than the session cookie

    You don’t have anything else to do from what I can tell.
    The TTL of the key in redis will be reset/update at the max age of the cookie, here 1 minute, and you should see the expiration date of the cookie update in the browser too.

    Maybe the custom middleware you made hijacked the cookie value send in the response

    Tell me if it helps you. If something still feels strange to you, tell me in comment and I will update my response.

    Cheers !

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search