diff --git a/.infra/index.ts b/.infra/index.ts index ad12392927..7c3b82bd0e 100644 --- a/.infra/index.ts +++ b/.infra/index.ts @@ -102,14 +102,14 @@ const redis = new Redis(`${name}-redis`, { isAdhocEnv, name: `${name}-redis`, tier: 'BASIC', - memorySizeGb: 1, + memorySizeGb: 2, region: location, authEnabled: true, redisVersion: 'REDIS_7_2', labels: { app: name }, redisConfigs: { 'maxmemory-policy': 'volatile-ttl', - 'maxmemory-gb': '0.95', + 'maxmemory-gb': '1.9', }, maintenancePolicy: { weeklyMaintenanceWindows: [ diff --git a/__tests__/boot.ts b/__tests__/boot.ts index fae16a969e..215da3b50c 100644 --- a/__tests__/boot.ts +++ b/__tests__/boot.ts @@ -710,6 +710,37 @@ describe('logged in boot', () => { }); }); + it('should boot logged in user and refresh jwt when token expires within 3 minutes', async () => { + const accessToken = await signJwt( + { + userId: '1', + roles: [], + }, + 2 * 60 * 1000, + ); + const key = app.signCookie(accessToken.token); + const res = await request(app.server) + .get(BASE_PATH) + .set('User-Agent', TEST_UA) + .set('Cookie', `${cookies.auth.key}=${key};`) + .expect(200); + + expect(res.body).toEqual({ + ...LOGGED_IN_BODY, + user: { + ...LOGGED_IN_BODY.user, + canSubmitArticle: + LOGGED_IN_BODY.user.reputation >= submitArticleThreshold, + }, + }); + + const authCookie = setCookieParser.parse(res, { map: true })[ + cookies.auth.key + ]; + expect(authCookie?.value).toBeTruthy(); + expect(authCookie?.value).not.toEqual(key); + }); + it('should not re-issue JWT token when isPlus in payload is same as user', async () => { await saveFixtures(con, User, [ { diff --git a/__tests__/routes/betterAuth.ts b/__tests__/routes/betterAuth.ts index e263657309..ed089a576e 100644 --- a/__tests__/routes/betterAuth.ts +++ b/__tests__/routes/betterAuth.ts @@ -61,6 +61,12 @@ describe('betterAuth routes', () => { expect(options.account).toMatchObject({ modelName: 'ba_account', }); + expect(options.session).toMatchObject({ + modelName: 'ba_session', + storeSessionInDatabase: true, + expiresIn: 30 * 24 * 60 * 60, + updateAge: 24 * 60 * 60, + }); }); it('should forward native callback routes to BetterAuth handler', async () => { diff --git a/src/betterAuth.ts b/src/betterAuth.ts index 6c06822696..0084f4380c 100644 --- a/src/betterAuth.ts +++ b/src/betterAuth.ts @@ -12,7 +12,7 @@ import { triggerTypedEvent } from './common/typedPubsub'; import { sendEmail, CioTransactionalMessageTemplateId } from './common/mailing'; import { handleRegex } from './common/object'; import { validateAndTransformHandle } from './common/handles'; -import { ONE_DAY_IN_SECONDS } from './common/constants'; +import { ONE_DAY_IN_SECONDS, ONE_MONTH_IN_SECONDS } from './common/constants'; import { singleRedisClient } from './redis'; import { User } from './entity/user/User'; import { cookies, extractRootDomain } from './cookies'; @@ -398,7 +398,7 @@ export const getBetterAuthOptions = (pool: Pool): BetterAuthOptions => { session: { modelName: 'ba_session', storeSessionInDatabase: true, - expiresIn: 7 * ONE_DAY_IN_SECONDS, + expiresIn: ONE_MONTH_IN_SECONDS, updateAge: ONE_DAY_IN_SECONDS, }, account: { diff --git a/src/cookies.ts b/src/cookies.ts index 025f967301..112d509f47 100644 --- a/src/cookies.ts +++ b/src/cookies.ts @@ -1,5 +1,6 @@ import { CookieSerializeOptions } from '@fastify/cookie'; import { FastifyReply, FastifyRequest } from 'fastify'; +import { ONE_MONTH_IN_SECONDS } from './common/constants'; import { generateTrackingId } from './ids'; import { setTrackingId } from './tracking'; import { counters } from './telemetry'; @@ -62,7 +63,7 @@ export const cookies: { authSession: { key: env === 'production' ? '__Secure-dast' : 'dast', opts: { - maxAge: 60 * 60 * 24 * 7, + maxAge: ONE_MONTH_IN_SECONDS, signed: false, httpOnly: true, secure: env === 'production', diff --git a/src/routes/boot.ts b/src/routes/boot.ts index 0ea794f38e..1bffb6667a 100644 --- a/src/routes/boot.ts +++ b/src/routes/boot.ts @@ -919,6 +919,9 @@ export const getBootData = async ( middleware?: BootMiddleware, ): Promise => { const referrer = getBootReferrer(req); + const shouldRefreshJwt = + !req.accessToken?.expiresIn || + differenceInMinutes(req.accessToken.expiresIn, new Date()) <= 3; const baSessionCookie = req.cookies[cookies.authSession.key]; if (baSessionCookie) { @@ -933,14 +936,11 @@ export const getBootData = async ( req.userId = session.user.id; req.trackingId = req.userId; setTrackingId(req, res, req.trackingId); - const jwtValid = - req.accessToken?.expiresIn && - differenceInMinutes(req.accessToken.expiresIn, new Date()) > 3; return loggedInBoot({ con, req, res, - refreshToken: !jwtValid, + refreshToken: shouldRefreshJwt, middleware, userId: req.userId, }); @@ -957,16 +957,12 @@ export const getBootData = async ( setCookie(req, res, 'authSession', undefined); } - if ( - req.userId && - req.accessToken?.expiresIn && - differenceInMinutes(req.accessToken?.expiresIn, new Date()) > 3 - ) { + if (req.userId && req.accessToken?.expiresIn) { return loggedInBoot({ con, req, res, - refreshToken: false, + refreshToken: shouldRefreshJwt, middleware, userId: req.userId, });