I have a NestJs app with PassportJs, Express-Session and Redis as session storage. Actually, I'm trying to implement a remember-me feature and I'm facing a problem and can't see why it's not working. The session created succesfully inside the DB, without any error, except the cookie stored in the DB has cookie.maxAge = null and cookie.expires = null. Any idea ?
app.module.ts
export class AppModule implements NestModule{
constructor(@InjectConnection(ConnectionName.DB_ALPHA_REDIS_CONNECTION_NAME) private readonly connection: Redis) {}
configure(consumer: MiddlewareConsumer) {
consumer
.apply(
session({
name: process.env.ALPHA_AUTH_SESSION,
store: new RedisStore({ client: this.connection }),
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
rolling: false,
resave: false,
cookie:{ httpOnly: true, secure: false, sameSite: true }
}),
passport.initialize(),
passport.session(),
)
.forRoutes('*');
}
}
local-auth.guard.ts
@Injectable()
export class LocalAuthGuard extends AuthGuard('local'){
async canActivate(context: ExecutionContext){
const REQUEST = context.switchToHttp().getRequest()
const RESPONSE = context.switchToHttp().getResponse()
const BODY = plainToClass(LoginBody, REQUEST.body)
const ERRORS = await validate(BODY)
const ERR_MESSAGES = ERRORS.flatMap(({ constraints }) =>
Object.values(constraints),
);
if(ERR_MESSAGES.length > 0)
RESPONSE.status(404).send(buildResponse(404, 'There is some errors', ERR_MESSAGES))
REQUEST.sessionStore.ttl = BODY.rememberMe ? 60 * 60 : 60
REQUEST.session.cookie.maxAge = BODY.rememberMe ? 60 * 60 * 1000 : 60 * 1000
// return 3600 as expected
console.log( REQUEST.sessionStore.ttl)
/**
return as expected
cookie: {
path: '/',
_expires: 2023-06-20T00:24:26.712Z,
originalMaxAge: 3600000,
httpOnly: true,
secure: false,
sameSite: true
}
Inside redis cookie.originalMaxAge = null
cookie.expires = null
*/
console.log( REQUEST.session.cookie)
const RESULT = (await super.canActivate(context)) as boolean
await super.logIn(REQUEST)
return RESULT
}
}
Inside redis DB:
{"cookie":{"originalMaxAge":null,"expires":null,"secure":false,"httpOnly":true,"path":"/","sameSite":true},"passport":{"user":{"id":"648a59999f34ed94915ed3ba"}}}
I think a possible solution is to use REQUEST.session.save() in LocalAuthGuard's canActivate method to ensure that the session is saved correctly after changing maxAge and ttl. You can try the following changes:
@Injectable()
export class LocalAuthGuard extends AuthGuard('local'){
async canActivate(context: ExecutionContext){
const REQUEST = context.switchToHttp().getRequest()
const RESPONSE = context.switchToHttp().getResponse()
const BODY = plainToClass(LoginBody, REQUEST.body)
const ERRORS = await validate(BODY)
const ERR_MESSAGES = ERRORS.flatMap(({ constraints }) =>
Object.values(constraints),
);
if(ERR_MESSAGES.length > 0)
RESPONSE.status(404).send(buildResponse(404, 'There are some errors', ERR_MESSAGES))
REQUEST.sessionStore.ttl = BODY.rememberMe ? 60 * 60 : 60
REQUEST.session.cookie.maxAge = BODY.rememberMe ? 60 * 60 * 1000 : 60 * 1000
// Save the session after modifying ttl and maxAge
REQUEST.session.save(err => {
if (err) {
console.error(err);
}
});
// return 3600 as expected
console.log( REQUEST.sessionStore.ttl)
/**
return as expected
cookie: {
path: '/',
',
_expires: 2023-06-20T00:24:26.712Z,
originalMaxAge: 3600000,
httpOnly: true,
secure: false,
sameSite: true
}
*/
console.log( REQUEST.session.cookie)
const RESULT = (await super.canActivate(context)) as boolean
await super.logIn(REQUEST)
return RESULT
}
}
another solution, try setting maxAge and ttl after calling super.logIn(REQUEST). :
@Injectable()
export class LocalAuthGuard extends AuthGuard('local'){
async canActivate(context: ExecutionContext){
const REQUEST = context.switchToHttp().getRequest()
const RESPONSE = context.switchToHttp().getResponse()
const BODY = plainToClass(LoginBody, REQUEST.body)
const ERRORS = await validate(BODY)
const ERR_MESSAGES = ERRORS.flatMap(({ constraints }) =>
Object.values(constraints),
);
if(ERR_MESSAGES.length > 0)
RESPONSE.status(404).send(buildResponse(404, 'There is some errors', ERR_MESSAGES))
const RESULT = (await super.canActivate(context)) as boolean
await super.logIn(REQUEST)
REQUEST.sessionStore.ttl = BODY.rememberMe ? 60 * 60 : 60
REQUEST.session.cookie.maxAge = BODY.rememberMe ? 60 * 60 * 1000 : 60 * 1000
// Save the session after modifying ttl and maxAge
REQUEST.session.save(err => {
if (err) {
console.error(err);
}
});
// return 3600 as expected
console.log( REQUEST.sessionStore.ttl)
/**
return as expected
cookie: {
path: '/',
_expires: 2023-06-20T00:24:26.712Z,
originalMaxAge: 3600000,
httpOnly: true,
secure: false,
sameSite: true
}
*/
console.log( REQUEST.session.cookie)
return RESULT
}
}