In business logic, we sometimes need to change session duration for users with specific conditions. It might be user permissions or security policies. When we manage a session on the server side with express-session, for example, it would not be a problem as we store user data on the server side, and on the client side, we keep identification tokens only. On the other hand, if we rely on the client side to store session information like JWT or session in cookies, we need to have some mechanics to update information on request. This article will cover the cookie-session JS package with the passport.js library on the express server.

User model

Let’s consider the situation when we have two users, Alice and Bob, and the server default is a one-hour session lifetime. We want to update the session lifetime based on the user parameter shortSession. These users we represent with the model:

export interface User {  
  id: string  
  name: string  
  email: string  
  password: string  
  shortSession: boolean  
}

And populate with the data:

export const users: User[] = [  
  {    id: '1',  
    name: 'Alice',  
    email: 'alice@example.com',  
    password: 'password',  
    shortSession: false,  
  },  
  {  
    id: '2',  
    name: 'Bob',  
    email: 'bob@example.com',  
    password: 'password',  
    shortSession: true,  
  },  
]

This model we will use in the passport serialization and deserialization:

passport.serializeUser((user, done) => {  
  done(null, user.id)  
})  
  
passport.deserializeUser((id, done) => {  
  const user = users.find((u) => u.id === id)  
  done(null, user)  
})

Simple frontend implementation

As per the frontend application, we will use a simple EJS template with an HTML login form (see src/views/index.ejs for details). After a successful login, we will echo the console user information and session options.

Our login endpoint is accessible with the POST method to the /login URL.

app.post(  
  '/login',  
  
  passport.authenticate('local', {  
    failureRedirect: '/',  
  }),  
  (req, res) => {  
    console.log(req.user)  
    console.log(req.sessionOptions)  
    res.status(200).send('logged in!')  
  },  
)

To connect the cookie-session package we need to pass configuration options:

app.use(  
  cookieSession({  
    secret: 'super secret key',  
    name: 'sessions',  
    maxAge: 24 * 60 * 60 * 1000, // 1 day  
    secure: false,  
    keys: ['Qjkdffks', 'KJKJSDrefjk3jk'],  
  }),  
)

You may notice that we set the default cookie lifetime in the maxAge parameter.

Passport.js configuration

And to check the user password, we will implement a simple auth check in the passport.js file:

passport.use(  
  new Strategy({ passReqToCallback: true }, (req, username, password, done) => {  
    console.log('username', username)  
    const user = users.find((user) => user.email === username)  
    if (!user) {  
      return done(null, false)  
    }  
  
    const valid = password === user.password  
    if (!valid) {  
      return done(null, false, { message: 'Incorrect username or password.' })  
    }  
  
    return done(null, user)  
  }),  
)

In this configuration, all our users, after successful login, will have one day of session liftime.

User specific session lifetime

In order to modify the session for the specific user we should use sessionOptions object populated by the cookieSession middleware we connected to the express. This object is used to override configuration defaults.

Let’s add our condition and desired parameters:

if (user.shortSession) {  
  req.sessionOptions.maxAge = 1000  
}

That it! The full code block looks like:

passport.use(  
  new Strategy({ passReqToCallback: true }, (req, username, password, done) => {  
    console.log('username', username)  
    const user = users.find((user) => user.email === username)  
    if (!user) {  
      return done(null, false)  
    }  
  
    const valid = password === user.password  
    if (!valid) {  
      return done(null, false, { message: 'Incorrect username or password.' })  
    }  
    if (user.shortSession) {  
      req.sessionOptions.maxAge = 1000  
    }  
  
    return done(null, user)  
  }),  
)

After we login as Bob, we will have a session lifetime of 1000 seconds. And we can see the updated session lifetime in the server console.

Security notes of the example in the repository

Security considerations. In order to work with the passport and cookie-session, I use the 5th version of the passport library. This version has a security vulnerability https://www.cve.org/CVERecord?id=CVE-2022-25896. For cookie-based sessions, this is not applicable. However, if you use different strategies in your project or other features, you should take into consideration that in the 6th version, the passport library introduces breaking changes, forcing auth strategies to support session revocation. As cookie-session by definition of browser cookies can’t be revoked, the author of the cookie-session library decided not to support this functionality, as this would contain meaningless code in the cookie-session. https://github.com/expressjs/cookie-session/issues/166 With full respect to this decision, we can use a workaround with a monkey patching cookie-session object and add the required empty functions to the cookie-session prototype. https://github.com/jaredhanson/passport/issues/904#issuecomment-1307558283

The full source code of the article and instruction how to run your local test environment may be found here: https://github.com/a13xg0/express-alter-cookie-sessions