llm-router / apps /api /src /middleware /auth.test.ts
ClaraSu's picture
Upload folder using huggingface_hub
0dbdd4f verified
Raw History Blame Contribute Delete
6.19 kB
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<string, string> } = {}) {
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()
})
})