mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
Currently, sessions timeouts and reuse interval inputs accepted any values. This PR caps: - absolute session timeout to 1 year - inactivity timeout to 1 year - refresh token reuse interval to 300 seconds Since these maximums are introduced _after_ some projects have values that exceed the new limits, we allow the users to save the form if their values exceed the max but are unchanged. However, if they decide to change the value, it must fit within the limits. <img width="1195" height="402" alt="Screenshot 2026-08-20 at 15 45 49" src="https://github.com/user-attachments/assets/192420e8-4878-4e4b-9d82-0d1cc4074728" /> <img width="1194" height="512" alt="Screenshot 2026-08-20 at 15 46 06" src="https://github.com/user-attachments/assets/bb333c54-daa3-46ac-b144-96263428f4d7" /> <img width="1168" height="323" alt="Screenshot 2026-08-20 at 15 46 35" src="https://github.com/user-attachments/assets/ae38fcf6-bc73-453f-a61b-2d6f2d0ecfee" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Added clear maximum-value guidance for session and refresh-token settings. * Existing projects with previously configured values above new limits can retain those values while making unrelated changes. * Removed session-related settings from the protection authentication form. * **Bug Fixes** * Improved validation for session timeouts, JWT expiration, and refresh-token reuse intervals. * Added clearer validation messages and support for reducing previously over-limit values. * **Tests** * Expanded coverage for boundary values, invalid inputs, saved settings, and submitted configuration updates. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import * as z from 'zod'
|
|
|
|
export const MAX_JWT_EXP = 604800
|
|
|
|
export const MAX_SESSIONS_TIMEBOX_HOURS = 8760 // 1 year
|
|
export const MAX_SESSIONS_INACTIVITY_TIMEOUT_HOURS = 8760 // 1 year
|
|
export const MAX_REFRESH_TOKEN_REUSE_INTERVAL_SECONDS = 300 // 5 mins
|
|
|
|
export const MAX_SESSIONS_TIMEBOX_MESSAGE = `Must be ${MAX_SESSIONS_TIMEBOX_HOURS} hours (1 year) or less`
|
|
export const MAX_SESSIONS_INACTIVITY_TIMEOUT_MESSAGE = `Must be ${MAX_SESSIONS_INACTIVITY_TIMEOUT_HOURS} hours (1 year) or less`
|
|
export const MAX_REFRESH_TOKEN_REUSE_INTERVAL_MESSAGE = `Must be ${MAX_REFRESH_TOKEN_REUSE_INTERVAL_SECONDS} seconds (5 minutes) or less`
|
|
|
|
const isWithinMaxOrUnchanged = (max: number, savedValue: number) => (value: number) =>
|
|
value <= max || value === savedValue
|
|
|
|
export const AccessTokenSchema = z.object({
|
|
JWT_EXP: z.coerce
|
|
.number()
|
|
.int('Must be a whole number')
|
|
.positive('Must be greater than 0')
|
|
.max(MAX_JWT_EXP, `Must be less than ${MAX_JWT_EXP}`),
|
|
})
|
|
|
|
export type AccessTokenFormValues = z.infer<typeof AccessTokenSchema>
|
|
|
|
export const createRefreshTokenSchema = ({ savedReuseInterval }: { savedReuseInterval: number }) =>
|
|
z.object({
|
|
REFRESH_TOKEN_ROTATION_ENABLED: z.boolean(),
|
|
SECURITY_REFRESH_TOKEN_REUSE_INTERVAL: z.coerce
|
|
.number()
|
|
.min(0, 'Must be 0 or greater')
|
|
.refine(
|
|
isWithinMaxOrUnchanged(MAX_REFRESH_TOKEN_REUSE_INTERVAL_SECONDS, savedReuseInterval),
|
|
MAX_REFRESH_TOKEN_REUSE_INTERVAL_MESSAGE
|
|
),
|
|
})
|
|
|
|
export type RefreshTokenFormValues = z.infer<ReturnType<typeof createRefreshTokenSchema>>
|
|
|
|
export const createUserSessionsSchema = ({
|
|
savedTimebox,
|
|
savedInactivityTimeout,
|
|
}: {
|
|
savedTimebox: number
|
|
savedInactivityTimeout: number
|
|
}) =>
|
|
z.object({
|
|
SESSIONS_TIMEBOX: z.coerce
|
|
.number()
|
|
.min(0, 'Must be 0 or greater')
|
|
.refine(
|
|
isWithinMaxOrUnchanged(MAX_SESSIONS_TIMEBOX_HOURS, savedTimebox),
|
|
MAX_SESSIONS_TIMEBOX_MESSAGE
|
|
),
|
|
SESSIONS_INACTIVITY_TIMEOUT: z.coerce
|
|
.number()
|
|
.multipleOf(0.1, 'Must be a multiple of 0.1')
|
|
.min(0, 'Must be 0 or greater')
|
|
.refine(
|
|
isWithinMaxOrUnchanged(MAX_SESSIONS_INACTIVITY_TIMEOUT_HOURS, savedInactivityTimeout),
|
|
MAX_SESSIONS_INACTIVITY_TIMEOUT_MESSAGE
|
|
),
|
|
SESSIONS_SINGLE_PER_USER: z.boolean(),
|
|
})
|
|
|
|
export type UserSessionsFormValues = z.infer<ReturnType<typeof createUserSessionsSchema>>
|