Next.js API route middleware: compose, validation, CSRF protection, and security headers
npm install @philiprehberger/next-api-middlewareNext.js API route middleware: compose, validation, CSRF protection, rate limiting, and security headers
npm install @philiprehberger/next-api-middleware
import { compose, withMethod, withValidation } from '@philiprehberger/next-api-middleware';
import { z } from 'zod';
const schema = z.object({ name: z.string(), email: z.string().email() });
export const POST = compose(
withMethod('POST'),
withValidation(schema),
async (req, ctx) => {
const data = ctx.data.validated;
return Response.json({ success: true, data });
}
);
import { compose, csrfProtection } from '@philiprehberger/next-api-middleware';
export const POST = compose(
csrfProtection({ allowedOrigins: ['https://example.com'] }),
async (req, ctx) => {
return Response.json({ ok: true });
}
);
import { applySecurityHeaders } from '@philiprehberger/next-api-middleware';
import { NextResponse } from 'next/server';
export function middleware(request) {
const response = NextResponse.next();
applySecurityHeaders(response.headers);
return response;
}
import { compose, rateLimit } from '@philiprehberger/next-api-middleware';
export const GET = compose(
rateLimit({ windowMs: 60000, maxRequests: 30 }),
async (req) => Response.json({ data: 'ok' })
);
import { compose, withCors, applyCorsHeaders } from '@philiprehberger/next-api-middleware';
const cors = { origin: ['https://app.example.com'], credentials: true };
export const POST = compose(
withCors(cors),
async (req) => {
const result = Response.json({ ok: true });
return applyCorsHeaders(result, req, cors);
},
);
withCors short-circuits OPTIONS preflight with a 204 + the right headers. Use applyCorsHeaders to decorate the route's actual response on non-preflight requests.
| Function | Signature | Description |
|---|---|---|
compose | (...middlewares: MiddlewareHandler[]) => (req, params?) => Promise<Response> | Chain middlewares. Returns 404 if none return a Response. |
pipe | (...middlewares: MiddlewareHandler[]) => (handler: MiddlewareHandler) => composed | Create a reusable middleware pipeline, then attach a handler. |
| Function | Signature | Description |
|---|---|---|
withValidation | (schema: { parse(data): T }, source?: 'body' | 'query' | 'params') => MiddlewareHandler | Validate request data. Parsed result stored in ctx.data.validated. |
withMethod | (...methods: string[]) => MiddlewareHandler | Restrict to specified HTTP methods. Returns 405 if not allowed. |
| Function | Signature | Description |
|---|---|---|
csrfProtection | (options?: CsrfOptions) => MiddlewareHandler | Validates CSRF token on unsafe methods (POST, PUT, DELETE, PATCH). |
generateCsrfToken | (options?: CsrfOptions) => { token, cookieName, headerName } | Generate a CSRF token and config for client-side usage. |
CsrfOptions: headerName (default: "x-csrf-token"), cookieName (default: "__csrf"), tokenLength (default: 32), allowedOrigins (skip token check for trusted origins)
| Function | Signature | Description |
|---|---|---|
applySecurityHeaders | (headers: Headers, options?: SecurityHeadersOptions) => void | Apply security headers to a Headers object. |
createSecurityHeadersConfig | (overrides?: SecurityHeadersOptions) => Record<string, string> | Get a plain object of security headers for manual use. |
| Function | Signature | Description |
|---|---|---|
rateLimit | (options?: RateLimitOptions) => MiddlewareHandler | In-memory rate limiter. Returns 429 when exceeded. |
RateLimitOptions: windowMs (default: 60000), maxRequests (default: 60), keyGenerator (default: x-forwarded-for), message.
| Function | Signature | Description |
|---|---|---|
withCors | (options?: CorsOptions) => MiddlewareHandler | Handle CORS preflight (OPTIONS) by returning 204 with allow headers. |
applyCorsHeaders | (response, req, options?) => Response | Decorate a non-preflight response with CORS headers. |
CorsOptions: origin (string | string[] | RegExp | (origin) => boolean | '*', default '*'), methods, allowedHeaders, exposedHeaders, credentials, maxAge.
allowedOrigins — when set, requests from listed origins skip token validation entirely (trusted origin bypass). Requests from other origins still require a valid CSRF token.npm install
npm run build
npm test
If you find this project useful: