diff --git a/openspec/changes/code-review-fix/tasks.md b/openspec/changes/code-review-fix/tasks.md index 9de7ef5..cbe64bf 100644 --- a/openspec/changes/code-review-fix/tasks.md +++ b/openspec/changes/code-review-fix/tasks.md @@ -19,7 +19,7 @@ ## 3. Authentication -- [ ] 3.1 `[sonnet]` Create `src/middleware.ts` with API key auth middleware: read `API_KEY` env var, check `X-API-Key` header on all `/api/*` routes except `/api/health`, return 401 if invalid +- [x] 3.1 `[sonnet]` Create `src/middleware.ts` with API key auth middleware: read `API_KEY` env var, check `X-API-Key` header on all `/api/*` routes except `/api/health`, return 401 if invalid - [ ] 3.2 `[sonnet]` Add FastAPI `Depends()` API key dependency in `services/ml/app/main.py`: read `API_KEY` env var, check `X-API-Key` header, exempt `/health` endpoint - [ ] 3.3 `[sonnet]` Update all Next.js proxy routes to forward `X-API-Key` header to ML service - [ ] 3.4 `[haiku]` Add `API_KEY` to `.env.example` with placeholder value and instructions diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..dda9010 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,33 @@ +import { NextResponse } from "next/server"; +import type { NextRequest } from "next/server"; + +export function middleware(request: NextRequest) { + const { pathname } = request.nextUrl; + + // Skip auth check for the health endpoint + if (pathname === "/api/health") { + return NextResponse.next(); + } + + const apiKey = process.env.API_KEY; + + // If API_KEY is not configured, skip auth check (fail-open for development) + if (!apiKey) { + console.warn( + "Warning: API_KEY environment variable is not set. API authentication is disabled." + ); + return NextResponse.next(); + } + + const requestApiKey = request.headers.get("X-API-Key"); + + if (!requestApiKey || requestApiKey !== apiKey) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + return NextResponse.next(); +} + +export const config = { + matcher: ["/api/:path*"], +};