Replaces the no-op fastify.authenticate stub and the never-implemented
identity/auth login with real bcrypt password verification, JWT session
issuance/verification (reusing the existing JWT_SECRET), and a Redis-backed
revocation denylist for logout. Adds requireRole('ADMIN') to admin-only
configuration writes across 002-009 that previously relied on a decorator
that never actually checked anything. Adds self-identity (GET /auth/me,
re-validated against live account state) and admin-provisioned accounts
(POST /admin/users).
Making the auth check genuinely reject invalid/missing tokens exposed that
~18 pre-existing integration test files called already-gated routes with no
Authorization header (safe against the old no-op stub, broken against a real
one) — fixed via a shared tests/helpers/auth.ts (loginAs/authHeader) and a
file-by-file pass, plus two related SLA-run cleanup races exposed once admin
setup calls in those files' own beforeAll blocks started actually succeeding.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
|
import { requireRole } from '@/modules/identity/auth/service/require-role';
|
|
|
|
function fakeRequest(user?: { role: string }): FastifyRequest {
|
|
return { user } as unknown as FastifyRequest;
|
|
}
|
|
|
|
describe('requireRole', () => {
|
|
it('passes when the session role is in the allowed list', async () => {
|
|
const guard = requireRole('ADMIN');
|
|
await expect(
|
|
guard(fakeRequest({ role: 'ADMIN' }), {} as FastifyReply),
|
|
).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('throws AuthorizationError when the session role is not in the allowed list', async () => {
|
|
const guard = requireRole('ADMIN');
|
|
await expect(guard(fakeRequest({ role: 'AGENT' }), {} as FastifyReply)).rejects.toMatchObject({
|
|
statusCode: 403,
|
|
});
|
|
});
|
|
|
|
it('throws AuthorizationError when there is no session at all', async () => {
|
|
const guard = requireRole('ADMIN');
|
|
await expect(guard(fakeRequest(undefined), {} as FastifyReply)).rejects.toMatchObject({
|
|
statusCode: 403,
|
|
});
|
|
});
|
|
|
|
it('accepts any role in a multi-role allow list', async () => {
|
|
const guard = requireRole('ADMIN', 'AGENT');
|
|
await expect(
|
|
guard(fakeRequest({ role: 'AGENT' }), {} as FastifyReply),
|
|
).resolves.toBeUndefined();
|
|
});
|
|
});
|