feat: add configurable session cookie name (#5425)

Added support for overriding the default session cookie name using the `INFRA.SESSION_COOKIE_NAME` config or the `SESSION_COOKIE_NAME` environment variable. This helps compatibility with proxies or load balancers that cannot handle cookie names containing dots.

---

Co-authored-by: mirarifhasan <arif.ishan05@gmail.com>
Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
Harshit Chandra 2025-10-28 13:45:08 +05:30 committed by GitHub
parent 8f7146bd57
commit 453b5fc088
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 68 additions and 3 deletions

View file

@ -127,6 +127,11 @@ export async function getDefaultInfraConfigs(): Promise<DefaultInfraConfig[]> {
value: encrypt(randomBytes(32).toString('hex')),
isEncrypted: true,
},
{
name: InfraConfigEnum.SESSION_COOKIE_NAME,
value: null,
isEncrypted: false,
},
{
name: InfraConfigEnum.TOKEN_SALT_COMPLEXITY,
value: '10',

View file

@ -734,6 +734,11 @@ export class InfraConfigService implements OnModuleInit {
return fail();
break;
case InfraConfigEnum.SESSION_COOKIE_NAME:
// Allow empty to fall back to default; otherwise enforce allowed characters
if (value && !/^[A-Za-z0-9_-]+$/.test(value)) return fail();
break;
default:
break;
}

View file

@ -49,8 +49,13 @@ async function bootstrap() {
app.use(
session({
// Allow overriding the default cookie name 'connect.sid' (which contains a dot).
// Some proxies/load balancers (like older Kong versions) cannot hash cookie names with dots,
// so we allow setting an alternative name via the INFRA.SESSION_COOKIE_NAME configuration.
name:
configService.get<string>('INFRA.SESSION_COOKIE_NAME') || 'connect.sid',
secret:
configService.get('INFRA.SESSION_SECRET') ||
configService.get<string>('INFRA.SESSION_SECRET') ||
crypto.randomBytes(16).toString('hex'),
}),
);

View file

@ -4,6 +4,7 @@ export enum InfraConfigEnum {
JWT_SECRET = 'JWT_SECRET',
SESSION_SECRET = 'SESSION_SECRET',
SESSION_COOKIE_NAME = 'SESSION_COOKIE_NAME',
TOKEN_SALT_COMPLEXITY = 'TOKEN_SALT_COMPLEXITY',
MAGIC_LINK_TOKEN_VALIDITY = 'MAGIC_LINK_TOKEN_VALIDITY',
REFRESH_TOKEN_VALIDITY = 'REFRESH_TOKEN_VALIDITY',

View file

@ -52,6 +52,9 @@
"refresh_token_validity": "Refresh Token Validity (in milliseconds)",
"access_token_validity": "Access Token Validity (in milliseconds)",
"session_secret": "Session Secret",
"session_cookie_name": "Session Cookie Name (optional)",
"session_cookie_name_help": "Only letters, numbers, underscore, and hyphen. Leave empty to use default 'connect.sid'.",
"session_cookie_name_invalid": "Invalid cookie name. Only letters, numbers, underscore, and hyphen allowed.",
"update_failure": "Failed to update token configurations!!"
},
"update_failure": "Failed to update authentication provider configurations!!"

View file

@ -133,6 +133,20 @@
</template>
</HoppSmartInput>
</div>
<div class="flex flex-col space-y-2">
<label>{{
t('configs.auth_providers.token.session_cookie_name')
}}</label>
<HoppSmartInput
v-model="authTokenConfig.fields.session_cookie_name"
placeholder="e.g., connect_sid"
:autofocus="false"
class="!my-2 !bg-primaryLight flex-1 border border-divider rounded"
/>
<p class="my-1 text-secondaryLight">
{{ t('configs.auth_providers.token.session_cookie_name_help') }}
</p>
</div>
</div>
</div>
</div>

View file

@ -28,12 +28,19 @@ import {
MICROSOFT_CONFIGS,
MOCK_SERVER_CONFIGS,
ServerConfigs,
TOKEN_VALIDATION_CONFIGS,
UpdatedConfigs,
} from '~/helpers/configs';
import { getCompiledErrorMessage } from '~/helpers/errors';
import { useToast } from './toast';
import { useClientHandler } from './useClientHandler';
const COOKIE_NAME_REGEX = /^[A-Za-z0-9_-]+$/;
const OPTIONAL_TOKEN_FIELD_KEYS = new Set(
TOKEN_VALIDATION_CONFIGS.filter((cfg) => cfg.optional).map((cfg) => cfg.key)
);
/** Composable that handles all operations related to server configurations
* @param updatedConfigs A Config Object containing the updated configs
*/
@ -154,6 +161,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
InfraConfigEnum.AccessTokenValidity
),
session_secret: getFieldValue(InfraConfigEnum.SessionSecret),
session_cookie_name: getFieldValue(InfraConfigEnum.SessionCookieName),
},
},
dataSharingConfigs: {
@ -286,8 +294,12 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
// This section has no enabled property, so we check fields directly
// for a valid number (>0) or non-empty string
if (section.name === 'token')
return Object.values(section.fields).some(isFieldNotValid);
if (section.name === 'token') {
return Object.entries(section.fields).some(
([key, value]) =>
!OPTIONAL_TOKEN_FIELD_KEYS.has(key) && isFieldNotValid(value)
);
}
// For rate limit section, we want to check if the values are not valid numbers
// and not empty strings
@ -573,6 +585,14 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
const sessionSecret = String(
updatedConfigs?.tokenConfigs.fields.session_secret
);
const sessionCookieName = String(
updatedConfigs?.tokenConfigs.fields.session_cookie_name || ''
);
// Validate cookie name: allow empty (falls back to default), else enforce pattern
if (sessionCookieName && !COOKIE_NAME_REGEX.test(sessionCookieName)) {
toast.error(t('configs.auth_providers.token.session_cookie_name_invalid'));
return false;
}
if (
isFieldEmpty(jwtSecret) ||
isFieldEmpty(tokenSaltComplexity) ||
@ -610,6 +630,10 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
name: InfraConfigEnum.SessionSecret,
value: sessionSecret,
},
{
name: InfraConfigEnum.SessionCookieName,
value: sessionCookieName,
},
];
return executeMutation(

View file

@ -67,6 +67,7 @@ export type ServerConfigs = {
refresh_token_validity: string;
access_token_validity: string;
session_secret: string;
session_cookie_name: string;
};
};
@ -116,6 +117,8 @@ export type ConfigSection = {
export type Config = {
name: InfraConfigEnum;
key: string;
// Marks fields that are optional and should be excluded from mandatory validation
optional?: boolean;
};
export const GOOGLE_CONFIGS: Config[] = [
@ -258,6 +261,11 @@ export const TOKEN_VALIDATION_CONFIGS: Config[] = [
name: InfraConfigEnum.SessionSecret,
key: 'session_secret',
},
{
name: InfraConfigEnum.SessionCookieName,
key: 'session_cookie_name',
optional: true,
},
{
name: InfraConfigEnum.TokenSaltComplexity,
key: 'token_salt_complexity',