Files
openmaic/OpenMAIC/tests/server/access-token.test.ts
2026-08-16 14:58:47 +08:00

76 lines
2.8 KiB
TypeScript

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,
);
});
});