Next.js cookbook · Intermediate
Protect routes in the Next.js App Router
Redirect signed-out users away from /dashboard and make sure server code never serves private data to them.
Approach
Use the request interceptor (middleware.ts, renamed proxy.ts in Next.js 16) for a fast, optimistic redirect based on the session cookie — but always verify the session again where data is read (Server Components, Server Actions, Route Handlers), typically in a cached verifySession() data-access helper. The interceptor alone is not a security boundary.
Solution
// proxy.ts (Next.js 16; use middleware.ts + `export function middleware` on 15)
import { NextResponse, type NextRequest } from "next/server";
export function proxy(request: NextRequest) {
const hasSession = request.cookies.has("session");
if (!hasSession) {
const url = new URL("/login", request.url);
url.searchParams.set("next", request.nextUrl.pathname);
return NextResponse.redirect(url);
}
return NextResponse.next();
}
export const config = { matcher: ["/dashboard/:path*", "/settings/:path*"] };
// lib/dal.ts — the real check, close to the data
import "server-only";
import { cache } from "react";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
export const verifySession = cache(async () => {
const token = (await cookies()).get("session")?.value;
const session = token ? await decryptSession(token) : null;
if (!session?.userId) redirect("/login");
return session;
});
// app/dashboard/page.tsx
export default async function Dashboard() {
const session = await verifySession();
const projects = await db.project.findMany({ where: { ownerId: session.userId } });
return <ProjectList projects={projects} />;
}
Pitfalls
- Relying only on middleware/proxy for authorization.
- Checking auth in a layout and assuming child pages are protected (layouts don't re-render on every navigation).
- Open redirects via the
nextparameter — only allow relative paths.
Variations
- Auth.js (
auth()), Clerk or Better Auth provide sessions and helpers. - Check roles in the DAL for admin-only data.
Further reading: Next.js: Authentication guide
Reference: https://nextjs.org/docs/app/guides/authentication
More Next.js recipes
- Add a Content Security Policy with nonces in Next.js
- Add dark mode to Next.js without a flash
- Add SEO metadata, Open Graph and sitemaps
- Avoid data-fetching waterfalls in Server Components
- Build a validated JSON API with Route Handlers
- Create encrypted session cookies in Next.js
- Handle errors and 404s in the App Router
- Handle forms with Server Actions and validation