# Next.js proxy.ts: the session refresh that keeps users signed in

Server Components cannot write cookies, so expired auth tokens never get refreshed there. The proxy (Next.js 16, `proxy.ts`; Next.js 15 and earlier, `middleware.ts`) runs before every request and does the refresh. Skip it and users get silently signed out when the access token expires, usually an hour after login.

## Checkable procedure

1. Create the proxy file with an `updateSession`-style function: build a `createServerClient` bound to `request.cookies`, call `await supabase.auth.getClaims()`, and return the response object.
2. `getClaims()`, not `getSession()`, inside server code. `getSession()` reads the cookie without verifying it, so a forged cookie renders another user's page. `getClaims()` verifies the token signature on every call.
3. Return the response that `setAll` last built. An earlier `NextResponse` object does not carry the refreshed cookies, so the browser keeps the old token and the user is signed out on the next request.
4. When you return a different response (a redirect, a rewrite), copy the cookies and the cache headers onto it first: `newResponse.cookies.setAll(supabaseResponse.cookies.getAll())`, plus `cache-control`, `expires`, `pragma`. The docs call this out explicitly because it is the most common break.
5. Add a matcher so the proxy skips routes that never touch Supabase (static assets, `_next`). Running it everywhere wastes a token verification per image request.

## Symptom check

"Works for an hour, then logged out" is the signature of a missing or broken proxy. "Logged out immediately after login" is usually the wrong response object being returned, check step 3 and 4.

## Quick test

Sign in, wait past the access-token expiry (default 3600s), then navigate. You should stay signed in with no visible refresh. Then try forging: it is enough to confirm server code paths call `getClaims()` and never branch on `getSession()` data.