import { afterEach, describe, expect, test, vi } from 'vitest'; import { createAccessToken, verifyAccessToken } from '@/lib/server/access-token'; import { verifyAccessTokenWithWebCrypto } from '@/lib/server/access-token-edge'; import { DEFAULT_ACCESS_CODE_SESSION_TTL_SECONDS, resolveAccessCodeSessionTtlSeconds, } from '@/lib/server/access-token-policy'; const NOW_MS = Date.parse('2026-06-25T00:00:00Z'); afterEach(() => { vi.unstubAllEnvs(); vi.useRealTimers(); }); describe('access token signing', () => { test('verifies tokens signed with the same access code', () => { const token = createAccessToken('demo-code', NOW_MS); expect(verifyAccessToken(token, 'demo-code', { nowMs: NOW_MS + 1 })).toBe(true); expect(verifyAccessToken(token, 'other-code', { nowMs: NOW_MS + 1 })).toBe(false); expect(verifyAccessToken('bad-token', 'demo-code', { nowMs: NOW_MS + 1 })).toBe(false); }); test('rejects expired and future-issued tokens at both Node and Edge boundaries', async () => { const token = createAccessToken('demo-code', NOW_MS); const ttlSeconds = 60; expect(verifyAccessToken(token, 'demo-code', { nowMs: NOW_MS + 59_999, ttlSeconds })).toBe( true, ); expect(verifyAccessToken(token, 'demo-code', { nowMs: NOW_MS + 60_000, ttlSeconds })).toBe( false, ); expect(verifyAccessToken(token, 'demo-code', { nowMs: NOW_MS - 1, ttlSeconds })).toBe(false); await expect( verifyAccessTokenWithWebCrypto(token, 'demo-code', { nowMs: NOW_MS + 60_000, ttlSeconds, }), ).resolves.toBe(false); await expect( verifyAccessTokenWithWebCrypto(token, 'demo-code', { nowMs: NOW_MS - 1, ttlSeconds, }), ).resolves.toBe(false); }); test('uses the same signature semantics in Node and Edge and rejects tampering', async () => { const token = createAccessToken('demo-code', NOW_MS); const tampered = `${token.slice(0, -1)}${token.endsWith('0') ? '1' : '0'}`; await expect( verifyAccessTokenWithWebCrypto(token, 'demo-code', { nowMs: NOW_MS + 1 }), ).resolves.toBe(true); await expect( verifyAccessTokenWithWebCrypto(tampered, 'demo-code', { nowMs: NOW_MS + 1 }), ).resolves.toBe(false); expect(verifyAccessToken(tampered, 'demo-code', { nowMs: NOW_MS + 1 })).toBe(false); }); test('resolves a configurable bounded TTL with a seven-day default', () => { expect(resolveAccessCodeSessionTtlSeconds(undefined)).toBe( DEFAULT_ACCESS_CODE_SESSION_TTL_SECONDS, ); expect(resolveAccessCodeSessionTtlSeconds('3600')).toBe(3600); expect(resolveAccessCodeSessionTtlSeconds('0')).toBe(DEFAULT_ACCESS_CODE_SESSION_TTL_SECONDS); expect(resolveAccessCodeSessionTtlSeconds('31536001')).toBe( DEFAULT_ACCESS_CODE_SESSION_TTL_SECONDS, ); }); });