Skip to content
Back to skills

798 Nextjs Middleware Creator B176b7f9

ASecurity

Create optimized Next.js middleware with authentication, rate limiting, and routing logic

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added May 31, 2026
developmenttypescriptgonextjstestingapisecurityperformance

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned May 31, 2026

npx -y skills add tools-only/X-Skills --skill 798-nextjs-middleware-creator_b176b7f9 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 798 Nextjs Middleware Creator B176b7f9?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 798 Nextjs Middleware Creator B176b7f9
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-798-nextjs-middleware-creator-b176b7f9/badge)](https://www.skillsdirectory.com/skills/tools-only-798-nextjs-middleware-creator-b176b7f9)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
allowed-tools: Read, Write, Edit
argument-hint: [middleware-type] [--auth] [--rate-limit] [--redirect] [--rewrite]
description: Create optimized Next.js middleware with authentication, rate limiting, and routing logic
---

## 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// __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
```typescript
// __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
```typescript
// 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
```typescript
// 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 in this skill

  • README.md948 B
  • skill.md18.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.