How to Use Middleware for Authentication in Next.js
In Next.js, use the
middleware.ts file to run code before requests reach your pages. You can check authentication by reading cookies or headers inside middleware and redirect unauthenticated users with NextResponse.redirect(). This protects routes globally or selectively.Syntax
The middleware.ts file exports a middleware function that receives a NextRequest object and returns a NextResponse. You can inspect cookies or headers to check authentication and decide to continue or redirect.
NextRequest: Represents the incoming request, lets you read cookies, headers, and URL.NextResponse: Used to continue the request or redirect.NextResponse.redirect(url): Redirects the user to a different page.
typescript
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { const token = request.cookies.get('token')?.value; if (!token) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); } export const config = { matcher: ['/protected/:path*'], };
Example
This example middleware protects all routes under /protected. It checks for a token cookie. If missing, it redirects to /login. Otherwise, it allows access.
typescript
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { const token = request.cookies.get('token')?.value; if (!token) { // Redirect unauthenticated users to login return NextResponse.redirect(new URL('/login', request.url)); } // Allow authenticated users to continue return NextResponse.next(); } // Apply middleware only to /protected routes export const config = { matcher: ['/protected/:path*'], };
Output
When visiting /protected or any subpath, unauthenticated users are redirected to /login; authenticated users see the protected content.
Common Pitfalls
- Not specifying
matcherinconfigcauses middleware to run on all routes, which may slow your app. - Forgetting to check cookies or headers correctly can cause false authentication results.
- Using client-side redirects instead of middleware redirects delays protection and exposes content briefly.
- Not handling public routes separately can block access unintentionally.
typescript
/* Wrong: Middleware runs on all routes and redirects without matcher */ import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { const token = request.cookies.get('token')?.value; if (!token) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); } /* Right: Use matcher to limit middleware to protected routes */ export const config = { matcher: ['/protected/:path*'], };
Quick Reference
| Concept | Description |
|---|---|
| middleware.ts | File where middleware function is defined |
| NextRequest | Object representing the incoming request, used to read cookies and URL |
| NextResponse.next() | Continue request to the next handler or page |
| NextResponse.redirect(url) | Redirect user to another URL |
| config.matcher | Specify which routes middleware applies to |
Key Takeaways
Use middleware.ts to run code before requests reach pages in Next.js.
Check authentication by reading cookies or headers inside middleware.
Redirect unauthenticated users with NextResponse.redirect() to protect routes.
Limit middleware scope using config.matcher to avoid slowing all routes.
Always test middleware to ensure it correctly protects intended routes.