Files
supabase/apps/studio/components/interfaces/Auth/SessionsAuthSettingsForm/SessionsAuthSettingsForm.test.tsx
T
fadymak 19dfbd250a feat(auth): expose access token expiry under auth settings (#48236)
Exposes the access token expiry (`JWT_EXP`) under `Auth -> Sessions`
settings as opposed to the Legacy JWT settings previously used.

<img width="1632" height="1199" alt="Screenshot 2026-07-23 at 10 06 33"
src="https://github.com/user-attachments/assets/85356e57-da95-404c-852a-21cf9cab2b74"
/>
<img width="1198" height="1119" alt="Screenshot 2026-07-23 at 10 06 19"
src="https://github.com/user-attachments/assets/bfa64b3b-1902-45eb-83ed-ca8bc12673af"
/>
<img width="1237" height="513" alt="Screenshot 2026-07-23 at 10 03 44"
src="https://github.com/user-attachments/assets/85779e9b-30f2-48c5-9faa-4c650d450227"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added an **Access Tokens** section to configure JWT expiration with
dedicated Save/Cancel controls and success/error toasts.
* Enforced a maximum JWT expiration value (must be **less than 604800
seconds**).
* **Bug Fixes**
* Updated the Sessions auth page text to better clarify configuration
for access tokens, refresh tokens, and user sessions.
* **Documentation**
* Updated JWT expiration guidance to point to **Auth settings → Access
Tokens** (replacing legacy JWT secret references).
* **Chores**
* Expanded automated tests covering Access Tokens saving and validation.
* **Refactor**
* Removed JWT expiration editing from the legacy JWT Secrets area,
consolidating it under Access Tokens.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-27 10:13:10 +02:00

107 lines
3.5 KiB
TypeScript

import { fireEvent, screen, waitFor, within } from '@testing-library/react'
import { mockAnimationsApi } from 'jsdom-testing-mocks'
import { HttpResponse } from 'msw'
import { describe, expect, test, vi } from 'vitest'
import { SessionsAuthSettingsForm } from './SessionsAuthSettingsForm'
import { customRender } from '@/tests/lib/custom-render'
import { addAPIMock } from '@/tests/lib/msw'
// FormMessage animates via framer-motion, which relies on the Web Animations API.
mockAnimationsApi()
vi.mock('@/lib/constants', async (importOriginal) => {
const actual = await importOriginal<typeof import('@/lib/constants')>()
return { ...actual, IS_PLATFORM: true }
})
vi.mock('@/hooks/misc/useCheckEntitlements', () => ({
useCheckEntitlements: () => ({ hasAccess: true, isLoading: false }),
}))
vi.mock('@/hooks/misc/useCheckPermissions', () => ({
useAsyncCheckPermissions: () => ({ can: true, isLoading: false, isSuccess: true }),
}))
function mockAuthConfig(overrides: Record<string, unknown> = {}) {
addAPIMock({
method: 'get',
path: '/platform/auth/:ref/config',
response: () =>
HttpResponse.json<any>({
JWT_EXP: 3600,
REFRESH_TOKEN_ROTATION_ENABLED: true,
SECURITY_REFRESH_TOKEN_REUSE_INTERVAL: 10,
SESSIONS_TIMEBOX: 0,
SESSIONS_INACTIVITY_TIMEOUT: 0,
SESSIONS_SINGLE_PER_USER: false,
...overrides,
}),
})
}
function mockUpdateAuthConfig(onPatch?: (body: unknown) => void) {
addAPIMock({
method: 'patch',
path: '/platform/auth/:ref/config',
response: async ({ request }) => {
const body = await request.json()
onPatch?.(body)
return HttpResponse.json<any>({ ...(body as object) })
},
})
}
describe('SessionsAuthSettingsForm — Access Tokens', () => {
test('renders the access token expiry from the auth config', async () => {
mockAuthConfig({ JWT_EXP: 3600 })
customRender(<SessionsAuthSettingsForm />)
expect(await screen.findByText('Access Tokens')).toBeInTheDocument()
expect(await screen.findByDisplayValue('3600')).toBeInTheDocument()
expect(screen.getByText('Access token expiry time')).toBeInTheDocument()
})
test('saving a new expiry issues a PATCH with the JWT_EXP payload', async () => {
mockAuthConfig({ JWT_EXP: 3600 })
let patchBody: unknown
mockUpdateAuthConfig((body) => {
patchBody = body
})
customRender(<SessionsAuthSettingsForm />)
const input = await screen.findByDisplayValue('3600')
fireEvent.change(input, { target: { value: '7200' } })
const form = input.closest('form') as HTMLFormElement
const saveButton = within(form).getByRole('button', { name: 'Save changes' })
await waitFor(() => expect(saveButton).toBeEnabled())
fireEvent.click(saveButton)
await waitFor(() => expect(patchBody).toEqual({ JWT_EXP: 7200 }))
})
test('blocks submit when the expiry exceeds the maximum', async () => {
mockAuthConfig({ JWT_EXP: 3600 })
let patchCalled = false
mockUpdateAuthConfig(() => {
patchCalled = true
})
customRender(<SessionsAuthSettingsForm />)
const input = await screen.findByDisplayValue('3600')
fireEvent.change(input, { target: { value: '999999' } })
const form = input.closest('form') as HTMLFormElement
const saveButton = within(form).getByRole('button', { name: 'Save changes' })
await waitFor(() => expect(saveButton).toBeEnabled())
fireEvent.click(saveButton)
expect(await screen.findByText('Must be less than 604800')).toBeInTheDocument()
expect(patchCalled).toBe(false)
})
})