import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import type { Request, Response, NextFunction, RequestHandler } from 'express' import { generateKeyPair, exportJWK, SignJWT } from 'jose' import { JwksClient, requireAuth, type AuthenticatedRequest } from '@llm-router/auth-client' import { createAuthMiddleware } from './auth.js' function makeReqRes(overrides: { path?: string; headers?: Record } = {}) { const req = { path: overrides.path ?? '/v1/expense/categories', headers: overrides.headers ?? {}, } as unknown as AuthenticatedRequest const res = { status: vi.fn().mockReturnThis(), json: vi.fn().mockReturnThis(), } as unknown as Response const next = vi.fn() as NextFunction return { req, res, next } } describe('createAuthMiddleware', () => { const originalInternalSecret = process.env['INTERNAL_SECRET'] beforeEach(() => { process.env['INTERNAL_SECRET'] = 'the-internal-secret' }) afterEach(() => { if (originalInternalSecret === undefined) delete process.env['INTERNAL_SECRET'] else process.env['INTERNAL_SECRET'] = originalInternalSecret }) it('exempts /health from auth without invoking the jwt verifier', () => { const jwtVerifier = vi.fn() as unknown as RequestHandler const middleware = createAuthMiddleware(jwtVerifier) const { req, res, next } = makeReqRes({ path: '/health' }) middleware(req, res, next) expect(next).toHaveBeenCalledOnce() expect(jwtVerifier).not.toHaveBeenCalled() }) it('bypasses the jwt verifier when x-internal-key matches INTERNAL_SECRET', () => { const jwtVerifier = vi.fn() as unknown as RequestHandler const middleware = createAuthMiddleware(jwtVerifier) const { req, res, next } = makeReqRes({ headers: { 'x-internal-key': 'the-internal-secret' } }) middleware(req, res, next) expect(next).toHaveBeenCalledOnce() expect(jwtVerifier).not.toHaveBeenCalled() }) it('bypasses the jwt verifier when the bearer token matches INTERNAL_SECRET', () => { const jwtVerifier = vi.fn() as unknown as RequestHandler const middleware = createAuthMiddleware(jwtVerifier) const { req, res, next } = makeReqRes({ headers: { authorization: 'Bearer the-internal-secret' } }) middleware(req, res, next) expect(next).toHaveBeenCalledOnce() expect(jwtVerifier).not.toHaveBeenCalled() }) it('delegates to the jwt verifier when no internal secret is presented', () => { const jwtVerifier = vi.fn((_req, _res, next: NextFunction) => next()) as unknown as RequestHandler const middleware = createAuthMiddleware(jwtVerifier) const { req, res, next } = makeReqRes({ headers: { authorization: 'Bearer some-jwt' } }) middleware(req, res, next) expect(jwtVerifier).toHaveBeenCalledOnce() }) it('delegates to the jwt verifier when the presented key does not match INTERNAL_SECRET', () => { const jwtVerifier = vi.fn((_req, _res, next: NextFunction) => next()) as unknown as RequestHandler const middleware = createAuthMiddleware(jwtVerifier) const { req, res, next } = makeReqRes({ headers: { 'x-internal-key': 'wrong-secret' } }) middleware(req, res, next) expect(jwtVerifier).toHaveBeenCalledOnce() }) it('propagates a 401 from the jwt verifier without calling next()', () => { const jwtVerifier = vi.fn((_req, res: Response) => { res.status(401).json({ error: 'Unauthorized' }) }) as unknown as RequestHandler const middleware = createAuthMiddleware(jwtVerifier) const { req, res, next } = makeReqRes({ headers: {} }) middleware(req, res, next) expect(next).not.toHaveBeenCalled() expect(res.status).toHaveBeenCalledWith(401) }) }) describe('createAuthMiddleware wired with the real requireAuth() from @llm-router/auth-client', () => { const originalInternalSecret = process.env['INTERNAL_SECRET'] beforeEach(() => { process.env['INTERNAL_SECRET'] = 'the-internal-secret' }) afterEach(() => { if (originalInternalSecret === undefined) delete process.env['INTERNAL_SECRET'] else process.env['INTERNAL_SECRET'] = originalInternalSecret }) async function setup() { const { publicKey, privateKey } = await generateKeyPair('ES256', { extractable: true }) const publicJwk = await exportJWK(publicKey) publicJwk['kid'] = 'test-key-1' publicJwk['alg'] = 'ES256' publicJwk['use'] = 'sig' const fetchImpl = vi.fn(async () => new Response(JSON.stringify({ keys: [publicJwk] }), { status: 200 })) const jwksClient = new JwksClient({ jwksUrl: 'https://auth.example.com/jwks', fetchImpl }) const middleware = createAuthMiddleware(requireAuth({ jwksClient })) return { middleware, privateKey } } it('populates req.auth for a request carrying a valid JWT issued by the real auth service', async () => { const { middleware, privateKey } = await setup() const token = await new SignJWT({ tenant_id: 'tenant-9', role: 'owner' }) .setProtectedHeader({ alg: 'ES256', kid: 'test-key-1' }) .setSubject('user-1') .setIssuedAt() .setExpirationTime('1h') .sign(privateKey) const { req, res, next } = makeReqRes({ headers: { authorization: `Bearer ${token}` } }) await middleware(req, res, next) expect(next).toHaveBeenCalledOnce() expect((req as AuthenticatedRequest).auth).toEqual({ userId: 'user-1', tenantId: 'tenant-9', role: 'owner' }) }) it('responds 401 for a request with a missing JWT and no internal secret', async () => { delete process.env['INTERNAL_SECRET'] const { middleware } = await setup() const { req, res, next } = makeReqRes({ headers: {} }) await middleware(req, res, next) expect(next).not.toHaveBeenCalled() expect(res.status).toHaveBeenCalledWith(401) }) it('still bypasses JWT verification for a valid internal secret, even with no bearer token', async () => { const { middleware } = await setup() const { req, res, next } = makeReqRes({ headers: { 'x-internal-key': 'the-internal-secret' } }) await middleware(req, res, next) expect(next).toHaveBeenCalledOnce() expect(res.status).not.toHaveBeenCalled() }) })