API routes in Next.js are powerful but require proper authentication to prevent unauthorized access. This guide covers essential patterns for securing your endpoints.
The Problem
By default, Next.js API routes are publicly accessible. Any route handler that modifies data or exposes sensitive information must verify the user's identity and permissions.
Using NextAuth.js
NextAuth.js provides a simple way to add authentication. Here's how to protect an API route:
// app/api/protected/route.ts
import { auth } from "@/auth";
import { NextResponse } from "next/server";
export async function GET() {
const session = await auth();
if (!session?.user) {
return NextResponse.json(
{ error: "Unauthorized" },
{ status: 401 }
);
}
// User is authenticated
return NextResponse.json({ data: "secret" });
}Middleware Pattern
For protecting multiple routes, use Next.js middleware:
// middleware.ts
import { auth } from "@/auth";
export default auth((req) => {
if (!req.auth && req.nextUrl.pathname.startsWith("/api/protected")) {
return Response.json(
{ error: "Unauthorized" },
{ status: 401 }
);
}
});
export const config = {
matcher: ["/api/protected/:path*"],
};What VibeCheck Detects
- VC-AUTH-001: Unprotected API routes that perform database writes without authentication checks
- VC-AUTH-002: Missing session validation in route handlers
- VC-AUTH-003: Hardcoded credentials or API keys
Best Practices
- Always check authentication at the start of route handlers
- Use middleware for route groups that all require auth
- Implement role-based access control for admin operations
- Return consistent error responses for auth failures
- Log authentication failures for security monitoring