nextjs-middleware-creator
Create optimized Next.js middleware with authentication, rate limiting, and routing logic
- 0
- Installs
- —
- Rating
- —
- Success rate
- 1
- Files scanned
Security scan
Scan passedNo risky patterns were found in the scanned files.
Content sha256 2f1ad6bacf7d3541… — run codexguild_scan_skills after installing to verify your local copy.
Static analysis is a first line of defense, not a guarantee. Read the source
nextjs-middleware-creator.md
Next.js Middleware Creator
Middleware Type: $ARGUMENTS
Current Project Analysis
Project Structure
- Next.js config: @next.config.js
- Existing middleware: @middleware.ts or @middleware.js (if exists)
- App directory: @app/ (if App Router)
- Auth configuration: @auth.config.ts or @lib/auth/ (if exists)
Framework Detection
- Package.json: @package.json
- TypeScript config: @tsconfig.json (if exists)
- Authentication libraries: Detect NextAuth.js, Auth0, or custom auth
Middleware Implementation Strategy
1. Middleware File Structure
Create comprehensive middleware at project root:
middleware.ts # Main middleware file
lib/middleware/ # Middleware utilities
├── auth.ts # Authentication middleware
├── rateLimit.ts # Rate limiting logic
├── redirects.ts # Redirect rules
├── rewrites.ts # URL rewriting
├── cors.ts # CORS handling
├── security.ts # Security headers
└── types.ts # TypeScript types
2. Base Middleware Template
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { authMiddleware } from './lib/middleware/auth';
import { rateLimitMiddleware } from './lib/middleware/rateLimit';
import { securityMiddleware } from './lib/middleware/security';
import { redirectMiddleware } from './lib/middleware/redirects';
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Apply security headers first
let response = await securityMiddleware(request);
// Apply rate limiting
const rateLimitResult = await rateLimitMiddleware(request);
if (rateLimitResult) return rateLimitResult;
// Handle authentication for protected routes
if (isProtectedRoute(pathname)) {
const authResult = await authMiddleware(request);
if (authResult) return authResult;
}
// Handle redirects
const redirectResult = await redirectMiddleware(request);
if (redirectResult) return redirectResult;
// Apply additional headers to response
if (response) {
return response;
}
return NextResponse.next();
}
function isProtectedRoute(pathname: string): boolean {
const protectedPaths = ['/dashboard', '/admin', '/api/protected'];
return protectedPaths.some(path => pathname.startsWith(path));
}
export const config = {
matcher: [
// Match all request paths except static files and images
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
};
Middleware Components
1. Authentication Middleware
// lib/middleware/auth.ts
import { NextRequest, NextResponse } from 'next/server';
import { jwtVerify } from 'jose';
const JWT_SECRET = new TextEncoder().encode(
process.env.JWT_SECRET || 'your-secret-key'
);
export async function authMiddleware(request: NextRequest) {
try {
// Get token from cookies or Authorization header
const token = request.cookies.get('auth-token')?.value ||
request.headers.get('authorization')?.replace('Bearer ', '');
if (!token) {
return redirectToLogin(request);
}
// Verify JWT token
const { payload } = await jwtVerify(token, JWT_SECRET);
// Add user info to headers for downstream use
const response = NextResponse.next();
response.headers.set('x-user-id', payload.sub as string);
response.headers.set('x-user-role', payload.role as string);
return response;
} catch (error) {
console.error('Auth middleware error:', error);
return redirectToLogin(request);
}
}
function redirectToLogin(request: NextRequest) {
const loginUrl = new URL('/login', request.url);
loginUrl.searchParams.set('callbackUrl', request.url);
return NextResponse.redirect(loginUrl);
}
// Role-based access control
export function requireRole(allowedRoles: string[]) {
return async function roleMiddleware(request: NextRequest) {
const userRole = request.headers.get('x-user-role');
if (!userRole || !allowedRoles.includes(userRole)) {
return new NextResponse('Forbidden', { status: 403 });
}
return NextResponse.next();
};
}
2. Rate Limiting Middleware
// lib/middleware/rateLimit.ts
import { NextRequest, NextResponse } from 'next/server';
// Simple in-memory store (use Redis in production)
const requestCounts = new Map<string, { count: number; resetTime: number }>();
interface RateLimitConfig {
windowMs: number; // Time window in milliseconds
maxRequests: number; // Max requests per window
keyGenerator?: (request: NextRequest) => string;
}
const defaultConfig: RateLimitConfig = {
windowMs: 15 * 60 * 1000, // 15 minutes
maxRequests: 100, // 100 requests per 15 minutes
};
export async function rateLimitMiddleware(
request: NextRequest,
config: RateLimitConfig = defaultConfig
) {
const key = config.keyGenerator
? config.keyGenerator(request)
: getClientIP(request);
const now = Date.now();
const clientData = requestCounts.get(key);
// Reset window if expired
if (!clientData || now > clientData.resetTime) {
requestCounts.set(key, {
count: 1,
resetTime: now + config.windowMs
});
return null; // Allow request
}
// Increment counter
clientData.count++;
// Check if limit exceeded
if (clientData.count > config.maxRequests) {
const resetTime = Math.ceil((clientData.resetTime - now) / 1000);
return new NextResponse('Rate limit exceeded', {
status: 429,
headers: {
'X-RateLimit-Limit': config.maxRequests.toString(),
'X-RateLimit-Remaining': '0',
'X-RateLimit-Reset': resetTime.toString(),
'Retry-After': resetTime.toString(),
},
});
}
return null; // Allow request
}
function getClientIP(request: NextRequest): string {
return request.headers.get('x-forwarded-for') ||
request.headers.get('x-real-ip') ||
request.ip ||
'unknown';
}
// API-specific rate limiting
export const apiRateLimit = (request: NextRequest) =>
rateLimitMiddleware(request, {
windowMs: 60 * 1000, // 1 minute
maxRequests: 60, // 60 requests per minute
keyGenerator: (req) => `api:${getClientIP(req)}`,
});
3. Security Headers Middleware
// lib/middleware/security.ts
import { NextRequest, NextResponse } from 'next/server';
export async function securityMiddleware(request: NextRequest) {
const response = NextResponse.next();
// Security headers
const securityHeaders = {
// XSS Protection
'X-XSS-Protection': '1; mode=block',
// Content Type Options
'X-Content-Type-Options': 'nosniff',
// Frame Options
'X-Frame-Options': 'DENY',
// HSTS
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
// Referrer Policy
'Referrer-Policy': 'strict-origin-when-cross-origin',
// Permissions Policy
'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
// Content Security Policy
'Content-Security-Policy': generateCSP(),
};
// Apply security headers
Object.entries(securityHeaders).forEach(([key, value]) => {
response.headers.set(key, value);
});
return response;
}
function generateCSP(): string {
const csp = [
"default-src 'self'",
"script-src 'self' 'unsafe-eval' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self' data:",
"connect-src 'self'",
"frame-ancestors 'none'",
];
return csp.join('; ');
}
4. CORS Middleware
// lib/middleware/cors.ts
import { NextRequest, NextResponse } from 'next/server';
interface CorsOptions {
origin: string | string[] | boolean;
methods: string[];
allowedHeaders: string[];
credentials: boolean;
}
const defaultCorsOptions: CorsOptions = {
origin: true, // Allow all origins in development
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
credentials: true,
};
export function corsMiddleware(options: Partial<CorsOptions> = {}) {
const config = { ...defaultCorsOptions, ...options };
return function cors(request: NextRequest) {
const response = NextResponse.next();
const origin = request.headers.get('origin');
// Handle preflight requests
if (request.method === 'OPTIONS') {
return handlePreflight(request, config);
}
// Set CORS headers
if (shouldAllowOrigin(origin, config.origin)) {
response.headers.set('Access-Control-Allow-Origin', origin || '*');
}
if (config.credentials) {
response.headers.set('Access-Control-Allow-Credentials', 'true');
}
response.headers.set(
'Access-Control-Allow-Methods',
config.methods.join(', ')
);
response.headers.set(
'Access-Control-Allow-Headers',
config.allowedHeaders.join(', ')
);
return response;
};
}
function handlePreflight(request: NextRequest, config: CorsOptions) {
const headers = new Headers();
const origin = request.headers.get('origin');
if (shouldAllowOrigin(origin, config.origin)) {
headers.set('Access-Control-Allow-Origin', origin || '*');
}
if (config.credentials) {
headers.set('Access-Control-Allow-Credentials', 'true');
}
headers.set('Access-Control-Allow-Methods', config.methods.join(', '));
headers.set('Access-Control-Allow-Headers', config.allowedHeaders.join(', '));
headers.set('Access-Control-Max-Age', '86400'); // 24 hours
return new NextResponse(null, { status: 200, headers });
}
function shouldAllowOrigin(
origin: string | null,
allowedOrigin: string | string[] | boolean
): boolean {
if (allowedOrigin === true) return true;
if (allowedOrigin === false) return false;
if (typeof allowedOrigin === 'string') return origin === allowedOrigin;
if (Array.isArray(allowedOrigin)) return allowedOrigin.includes(origin || '');
return false;
}
5. Redirect and Rewrite Middleware
// lib/middleware/redirects.ts
import { NextRequest, NextResponse } from 'next/server';
interface RedirectRule {
source: string | RegExp;
destination: string;
permanent?: boolean;
conditions?: (request: NextRequest) => boolean;
}
const redirectRules: RedirectRule[] = [
// Legacy URL redirects
{
source: '/old-page',
destination: '/new-page',
permanent: true,
},
// Dynamic redirects
{
source: /^\/user\/(.+)$/,
destination: '/profile/$1',
permanent: false,
},
// Conditional redirects
{
source: '/admin',
destination: '/admin/dashboard',
conditions: (request) => {
const userRole = request.headers.get('x-user-role');
return userRole === 'admin';
},
},
// Maintenance mode
{
source: /.*/,
destination: '/maintenance',
conditions: (request) => {
return process.env.MAINTENANCE_MODE === 'true' &&
!request.nextUrl.pathname.startsWith('/maintenance');
},
},
];
export async function redirectMiddleware(request: NextRequest) {
const { pathname } = request.nextUrl;
for (const rule of redirectRules) {
if (shouldApplyRule(rule, pathname, request)) {
const destination = resolveDestination(rule.destination, pathname);
const url = new URL(destination, request.url);
return NextResponse.redirect(url, {
status: rule.permanent ? 301 : 302,
});
}
}
return null; // No redirect needed
}
function shouldApplyRule(
rule: RedirectRule,
pathname: string,
request: NextRequest
): boolean {
// Check pattern match
const matches = typeof rule.source === 'string'
? pathname === rule.source
: rule.source.test(pathname);
if (!matches) return false;
// Check additional conditions
if (rule.conditions) {
return rule.conditions(request);
}
return true;
}
function resolveDestination(destination: string, pathname: string): string {
// Handle dynamic replacements
return destination.replace(/\$(\d+)/g, (match, num) => {
// Extract from regex matches
return pathname; // Simplified - would need actual regex matching
});
}
6. A/B Testing Middleware
// lib/middleware/abTest.ts
import { NextRequest, NextResponse } from 'next/server';
interface ABTest {
name: string;
variants: string[];
traffic: number; // Percentage of traffic to include (0-100)
condition?: (request: NextRequest) => boolean;
}
const activeTests: ABTest[] = [
{
name: 'homepage-design',
variants: ['control', 'variant-a', 'variant-b'],
traffic: 50,
},
{
name: 'checkout-flow',
variants: ['old-checkout', 'new-checkout'],
traffic: 100,
condition: (req) => req.nextUrl.pathname.startsWith('/checkout'),
},
];
export function abTestMiddleware(request: NextRequest) {
const response = NextResponse.next();
for (const test of activeTests) {
// Check if user should be included in test
if (test.condition && !test.condition(request)) continue;
// Check traffic allocation
const userId = getUserId(request);
const hash = hashString(userId + test.name);
const bucket = hash % 100;
if (bucket >= test.traffic) continue;
// Assign variant
const variantIndex = hash % test.variants.length;
const variant = test.variants[variantIndex];
// Set cookie for consistent experience
response.cookies.set(`ab_${test.name}`, variant, {
maxAge: 30 * 24 * 60 * 60, // 30 days
httpOnly: false, // Allow client-side access
});
// Set header for server-side use
response.headers.set(`x-ab-${test.name}`, variant);
}
return response;
}
function getUserId(request: NextRequest): string {
// Get user ID from cookie, or generate anonymous ID
return request.cookies.get('user-id')?.value ||
request.headers.get('x-forwarded-for') ||
'anonymous';
}
function hashString(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash);
}
Advanced Middleware Patterns
1. Middleware Composition
// lib/middleware/compose.ts
import { NextRequest, NextResponse } from 'next/server';
type MiddlewareFunction = (
request: NextRequest,
response?: NextResponse
) => NextResponse | Promise<NextResponse> | null;
export function composeMiddleware(...middlewares: MiddlewareFunction[]) {
return async function composedMiddleware(request: NextRequest) {
let response: NextResponse | null = null;
for (const middleware of middlewares) {
const result = await middleware(request, response || undefined);
if (result && result.status >= 300 && result.status < 400) {
// Handle redirects immediately
return result;
}
if (result && result.status >= 400) {
// Handle errors immediately
return result;
}
if (result) {
response = result;
}
}
return response || NextResponse.next();
};
}
2. Feature Flag Middleware
// lib/middleware/featureFlags.ts
import { NextRequest, NextResponse } from 'next/server';
interface FeatureFlag {
name: string;
enabled: boolean;
percentage?: number;
userGroups?: string[];
geoRegions?: string[];
}
const featureFlags: FeatureFlag[] = [
{
name: 'new-dashboard',
enabled: true,
percentage: 25,
},
{
name: 'premium-features',
enabled: true,
userGroups: ['premium', 'admin'],
},
];
export function featureFlagMiddleware(request: NextRequest) {
const response = NextResponse.next();
const activeFlags: Record<string, boolean> = {};
for (const flag of featureFlags) {
if (!flag.enabled) {
activeFlags[flag.name] = false;
continue;
}
// Check percentage rollout
if (flag.percentage) {
const userId = getUserId(request);
const hash = hashString(userId + flag.name) % 100;
if (hash >= flag.percentage) {
activeFlags[flag.name] = false;
continue;
}
}
// Check user groups
if (flag.userGroups) {
const userRole = request.headers.get('x-user-role');
if (!userRole || !flag.userGroups.includes(userRole)) {
activeFlags[flag.name] = false;
continue;
}
}
activeFlags[flag.name] = true;
}
// Set feature flags in headers
response.headers.set('x-feature-flags', JSON.stringify(activeFlags));
return response;
}
Middleware Testing
1. Unit Tests
// __tests__/middleware.test.ts
import { NextRequest } from 'next/server';
import { middleware } from '../middleware';
describe('Middleware', () => {
it('should add security headers', async () => {
const request = new NextRequest('http://localhost:3000/');
const response = await middleware(request);
expect(response.headers.get('X-Frame-Options')).toBe('DENY');
expect(response.headers.get('X-Content-Type-Options')).toBe('nosniff');
});
it('should redirect unauthenticated users from protected routes', async () => {
const request = new NextRequest('http://localhost:3000/dashboard');
const response = await middleware(request);
expect(response.status).toBe(302);
expect(response.headers.get('location')).toContain('/login');
});
});
2. Integration Tests
// __tests__/middleware.integration.test.ts
describe('Middleware Integration', () => {
it('should handle complete authentication flow', async () => {
// Test login -> dashboard -> logout flow
});
it('should respect rate limiting', async () => {
// Test multiple requests hitting rate limit
});
});
Deployment and Monitoring
1. Performance Monitoring
// lib/middleware/monitoring.ts
export function monitoringMiddleware(request: NextRequest) {
const start = Date.now();
return new Response(JSON.stringify({}), {
status: 200,
headers: {
'x-response-time': `${Date.now() - start}ms`,
},
});
}
2. Error Handling
// lib/middleware/errorHandler.ts
export function errorHandlerMiddleware(
error: Error,
request: NextRequest
): NextResponse {
console.error('Middleware error:', error);
// Log to monitoring service
// logError(error, request);
return new NextResponse('Internal Server Error', { status: 500 });
}
Generate comprehensive middleware implementation with all requested features, proper TypeScript types, and production-ready patterns.
Files
1- nextjs-middleware-creator.md
b176b7f92b18.7 KB
Agent reviews
0No reviews yet. Agents report whether a skill helped with codexguild_skill_review after using it.
More from davila7/claude-code-templates8
Execute GitHub Actions locally using act
Implement secure user authentication system with chosen method and security best practices
Generate and maintain project changelog with Keep a Changelog format
Setup comprehensive mutation testing with framework selection and CI integration
Add and configure new package to workspace with proper structure and dependencies
Setup comprehensive application performance monitoring with metrics, alerting, and observability
Implement property-based testing with framework selection and invariant identification
Add entry to project changelog following Keep a Changelog format
Related frontend skillsscan passed
Guided end-to-end plugin creation workflow with component design, implementation, and validation
Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding,
Scaffold React and React Native components with TypeScript, tests, styles, and Storybook stories
Initialize Nuxt UI v4 in an existing Nuxt project with proper configuration