AUTH STARTER · ROUTES & PROXY
Routes & proxy
How protected routes work, how the proxy handles them, and why you should never trust the proxy alone.
src/proxy.ts is the Next.js 16 replacement for middleware.ts. It runs before pages render, checks for a session cookie, and bounces users to the right place. The whole thing is driven by authConfig — to protect a new route, you don't edit the proxy, you add a prefix to the config.
Protecting a new route
// src/auth.config.ts
protection: {
protectedPrefixes: ["/dashboard", "/settings", "/account", "/admin"],
publicAuthPrefixes: ["/sign-in", "/sign-up", "/forgot-password", "/reset-password"],
},That's it. Anything starting with /admin is now protected. No proxy edits needed.
How the proxy decides
- Reads the session cookie by prefix (yourapp.session_token by default).
- If the path matches a protected prefix and there's no cookie → redirect to /sign-in?callbackUrl=<original>.
- If the path matches a public auth prefix (sign-in, sign-up) and there IS a cookie → redirect to /dashboard.
- Otherwise → pass through.
The proxy only checks cookie presence, not validity
It does NOT verify the session against the database. A user with a stale/forged/expired cookie still passes the proxy. ALWAYS re-validate inside Server Components with requireSession(). The proxy is an optimistic redirect for UX — not a security boundary.
The matcher
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};We skip /api because API routes handle their own auth. Static assets are skipped to avoid wasting cycles on every image request.
About callbackUrl
When the proxy redirects an unauthenticated user, it sets ?callbackUrl=<the-path-they-wanted>. The sign-in form reads that and routes them back after auth. If you customize sign-in, keep the callbackUrl handling intact — it's a UX win that costs nothing.