diff --git a/src/components/authentication/session.interceptor.ts b/src/components/authentication/session.interceptor.ts index 792912ce77..d3e37deced 100644 --- a/src/components/authentication/session.interceptor.ts +++ b/src/components/authentication/session.interceptor.ts @@ -97,7 +97,7 @@ export class SessionInterceptor implements NestInterceptor { } private getTokenFromCookie(req: IRequest | undefined): string | null { - return req?.cookies?.[this.config.sessionCookie.name] || null; + return req?.cookies?.[this.config.sessionCookie(req).name] || null; } getImpersonateeFromContext( diff --git a/src/components/authentication/session.resolver.ts b/src/components/authentication/session.resolver.ts index 5367bf2584..bb15a58fcc 100644 --- a/src/components/authentication/session.resolver.ts +++ b/src/components/authentication/session.resolver.ts @@ -72,7 +72,9 @@ export class SessionResolver { const userFromSession = session.anonymous ? undefined : session.userId; if (browser) { - const { name, expires, ...options } = this.config.sessionCookie; + const { name, expires, ...options } = this.config.sessionCookie( + context.request!, + ); if (!context.response) { throw new ServerException( 'Cannot use cookie session without a response object', diff --git a/src/core/config/config.service.ts b/src/core/config/config.service.ts index b58191b2f1..a323e9f356 100644 --- a/src/core/config/config.service.ts +++ b/src/core/config/config.service.ts @@ -17,7 +17,7 @@ import { ProgressReportStatus } from '../../components/progress-report/dto/progr import type { TransitionName as ProgressReportTransitionName } from '../../components/progress-report/workflow/transitions'; import { DefaultTimezoneWrapper } from '../email/templates/formatted-date-time'; import { FrontendUrlWrapper } from '../email/templates/frontend-url'; -import type { CookieOptions, CorsOptions } from '../http'; +import type { CookieOptions, CorsOptions, IRequest } from '../http'; import { LogLevel } from '../logger/logger.interface'; import { EnvironmentService } from './environment.service'; import { determineRootUser } from './root-user.config'; @@ -252,10 +252,9 @@ export const makeConfig = (env: EnvironmentService) => } satisfies CorsOptions; })(); - sessionCookie = ((): Merge< - CookieOptions, - { name: string; expires?: DurationLike } - > => { + sessionCookie = ( + req: IRequest, + ): Merge => { const name = env.string('SESSION_COOKIE_NAME').optional('cordsession'); let domain = env.string('SESSION_COOKIE_DOMAIN').optional(); @@ -265,6 +264,10 @@ export const makeConfig = (env: EnvironmentService) => domain = '.' + domain; } + const userAgent = req.headers['user-agent']; + const isSafari = + userAgent && /^((?!chrome|android).)*safari/i.test(userAgent); + return { name, domain, @@ -274,14 +277,14 @@ export const makeConfig = (env: EnvironmentService) => httpOnly: true, // All paths, not just the current one path: '/', - ...(!isDev && { + ...(!(isSafari && isDev) && { // Require HTTPS (required for SameSite) secure: true, // Allow 3rd party (other domains) sameSite: 'none', }), }; - })(); + }; xray = { daemonAddress: this.jest