M
Middleware
Type-safe Next.js middleware for authentication, redirects, and request modification.
Code
typescript
1// middleware.ts (in project root)2import { NextResponse } from "next/server";3import type { NextRequest } from "next/server";4 5// Types for JWT payload6interface JWTPayload {7 sub: string;8 email: string;9 role: "admin" | "user" | "guest";10 exp: number;11}12 13// Protected routes configuration14const protectedRoutes = ["/dashboard", "/profile", "/settings"];15const adminRoutes = ["/admin"];16const authRoutes = ["/login", "/register"];17 18// Simple JWT decoder (use a library in production)19function decodeToken(token: string): JWTPayload | null {20 try {21 const payload = token.split(".")[1];22 return JSON.parse(atob(payload));23 } catch {24 return null;25 }26}27 28export function middleware(request: NextRequest) {29 const { pathname } = request.nextUrl;30 const token = request.cookies.get("auth-token")?.value;31 32 // Decode and validate token33 const user = token ? decodeToken(token) : null;34 const isAuthenticated = user && user.exp * 1000 > Date.now();35 36 // Check if route is protected37 const isProtectedRoute = protectedRoutes.some((route) =>38 pathname.startsWith(route)39 );40 const isAdminRoute = adminRoutes.some((route) => pathname.startsWith(route));41 const isAuthRoute = authRoutes.some((route) => pathname.startsWith(route));42 43 // Redirect authenticated users away from auth pages44 if (isAuthRoute && isAuthenticated) {45 return NextResponse.redirect(new URL("/dashboard", request.url));46 }47 48 // Redirect unauthenticated users to login49 if (isProtectedRoute && !isAuthenticated) {50 const loginUrl = new URL("/login", request.url);51 loginUrl.searchParams.set("callbackUrl", pathname);52 return NextResponse.redirect(loginUrl);53 }54 55 // Check admin access56 if (isAdminRoute) {57 if (!isAuthenticated) {58 return NextResponse.redirect(new URL("/login", request.url));59 }60 if (user?.role !== "admin") {61 return NextResponse.redirect(new URL("/unauthorized", request.url));62 }63 }64 65 // Add user info to headers for server components66 const response = NextResponse.next();67 if (user) {68 response.headers.set("x-user-id", user.sub);69 response.headers.set("x-user-role", user.role);70 }71 72 return response;73}74 75// Configure which routes middleware runs on76export const config = {77 matcher: [78 /*79 * Match all request paths except for:80 * - api (API routes)81 * - _next/static (static files)82 * - _next/image (image optimization)83 * - favicon.ico (favicon file)84 */85 "/((?!api|_next/static|_next/image|favicon.ico).*)",86 ],87};88 89// middleware/withAuth.ts - Middleware composition helper90type MiddlewareHandler = (91 request: NextRequest92) => NextResponse | Promise<NextResponse>;93 94export function composeMiddleware(...handlers: MiddlewareHandler[]) {95 return async (request: NextRequest): Promise<NextResponse> => {96 for (const handler of handlers) {97 const response = await handler(request);98 if (response.status !== 200) {99 return response;100 }101 }102 return NextResponse.next();103 };104}Run this example locally
$ npx create-next-app@latest --typescript