refactor: drop redundant iat intersections and reuse JwtPayload in tests
JwtPayload already declares iat?: number, so the & { iat?: number } in
makeRequireAuth and slideSessionIfNeeded was a no-op. The unit test had a
local TestPayload duplicating the same shape — replaced with the canonical
import.
This commit is contained in:
@@ -33,7 +33,7 @@ export function issueSessionCookie(
|
||||
export function makeRequireAuth(config: Config) {
|
||||
return async function requireAuth(request: FastifyRequest, reply: FastifyReply): Promise<void> {
|
||||
try {
|
||||
const payload = await request.jwtVerify<JwtPayload & { iat?: number }>();
|
||||
const payload = await request.jwtVerify<JwtPayload>();
|
||||
slideSessionIfNeeded(request, reply, payload, request.server, config.cookieSecure);
|
||||
} catch {
|
||||
const isApi = request.url.startsWith('/api/');
|
||||
|
||||
@@ -7,7 +7,7 @@ import { issueSessionCookie } from './auth.ts';
|
||||
export function slideSessionIfNeeded(
|
||||
request: FastifyRequest,
|
||||
reply: FastifyReply,
|
||||
payload: JwtPayload & { iat?: number },
|
||||
payload: JwtPayload,
|
||||
server: FastifyInstance,
|
||||
cookieSecure: boolean,
|
||||
): void {
|
||||
|
||||
@@ -3,18 +3,13 @@ import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import fastifyCookie from '@fastify/cookie';
|
||||
import fastifyJwt from '@fastify/jwt';
|
||||
import { slideSessionIfNeeded } from '../../src/middleware/session-renewal.ts';
|
||||
import type { JwtPayload } from '../../src/types.ts';
|
||||
import {
|
||||
SESSION_COOKIE_NAME,
|
||||
SESSION_RENEW_THRESHOLD_SECONDS,
|
||||
SESSION_TTL_SECONDS,
|
||||
} from '../../src/constants.ts';
|
||||
|
||||
interface TestPayload {
|
||||
sub: number;
|
||||
username: string;
|
||||
iat?: number;
|
||||
}
|
||||
|
||||
async function buildTestServer(): Promise<FastifyInstance> {
|
||||
const app = Fastify();
|
||||
await app.register(fastifyCookie);
|
||||
@@ -60,7 +55,7 @@ describe('slideSessionIfNeeded', () => {
|
||||
|
||||
it('re-issues cookie when now - iat >= SESSION_RENEW_THRESHOLD_SECONDS', () => {
|
||||
const reply = fakeReply();
|
||||
const payload: TestPayload = {
|
||||
const payload: JwtPayload = {
|
||||
sub: 1,
|
||||
username: 'alice',
|
||||
iat: NOW_SEC - SESSION_RENEW_THRESHOLD_SECONDS,
|
||||
@@ -73,7 +68,7 @@ describe('slideSessionIfNeeded', () => {
|
||||
|
||||
it('skips re-issue when now - iat < SESSION_RENEW_THRESHOLD_SECONDS', () => {
|
||||
const reply = fakeReply();
|
||||
const payload: TestPayload = {
|
||||
const payload: JwtPayload = {
|
||||
sub: 1,
|
||||
username: 'alice',
|
||||
iat: NOW_SEC - (SESSION_RENEW_THRESHOLD_SECONDS - 1),
|
||||
@@ -84,35 +79,35 @@ describe('slideSessionIfNeeded', () => {
|
||||
|
||||
it('skips re-issue on /logout path', () => {
|
||||
const reply = fakeReply();
|
||||
const payload: TestPayload = { sub: 1, username: 'alice', iat: 0 }; // ancient
|
||||
const payload: JwtPayload = { sub: 1, username: 'alice', iat: 0 }; // ancient
|
||||
slideSessionIfNeeded(fakeRequest('/logout') as never, reply as never, payload, app, false);
|
||||
expect(reply.setCookieCalls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('skips re-issue on /api/v1/auth/logout path', () => {
|
||||
const reply = fakeReply();
|
||||
const payload: TestPayload = { sub: 1, username: 'alice', iat: 0 };
|
||||
const payload: JwtPayload = { sub: 1, username: 'alice', iat: 0 };
|
||||
slideSessionIfNeeded(fakeRequest('/api/v1/auth/logout') as never, reply as never, payload, app, false);
|
||||
expect(reply.setCookieCalls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('skips re-issue when /logout has a query string', () => {
|
||||
const reply = fakeReply();
|
||||
const payload: TestPayload = { sub: 1, username: 'alice', iat: 0 };
|
||||
const payload: JwtPayload = { sub: 1, username: 'alice', iat: 0 };
|
||||
slideSessionIfNeeded(fakeRequest('/logout?redirect=foo') as never, reply as never, payload, app, false);
|
||||
expect(reply.setCookieCalls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('treats missing iat as 0 (forces refresh)', () => {
|
||||
const reply = fakeReply();
|
||||
const payload: TestPayload = { sub: 1, username: 'alice' };
|
||||
const payload: JwtPayload = { sub: 1, username: 'alice' };
|
||||
slideSessionIfNeeded(fakeRequest('/upload') as never, reply as never, payload, app, false);
|
||||
expect(reply.setCookieCalls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('produces a cookie carrying Max-Age=SESSION_TTL_SECONDS', () => {
|
||||
const reply = fakeReply();
|
||||
const payload: TestPayload = { sub: 1, username: 'alice', iat: 0 };
|
||||
const payload: JwtPayload = { sub: 1, username: 'alice', iat: 0 };
|
||||
slideSessionIfNeeded(fakeRequest('/upload') as never, reply as never, payload, app, true);
|
||||
expect(reply.setCookieCalls[0].opts.maxAge).toBe(SESSION_TTL_SECONDS);
|
||||
expect(reply.setCookieCalls[0].opts.secure).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user