User clicks "Sign in with GitHub" → Supabase OAuth redirect → GitHub authorization → Callback to /auth/callback → Session cookie set → Middleware validates on every request → Protected pages render with user context
Middleware (Critical)
// middleware.tsexport async function middleware(request: NextRequest) { let supabaseResponse = NextResponse.next({ request }) const supabase = createServerClient(url, key, { cookies: ... }) // MUST call getUser() immediately after createServerClient const { data: { user } } = await supabase.auth.getUser() if (!user && isProtectedRoute(request.nextUrl.pathname)) { return NextResponse.redirect(new URL("/login", request.url)) } // MUST return supabaseResponse unchanged return supabaseResponse}
Key Rules
getUser() immediately after createServerClient in middleware
Return supabaseResponse unchanged (cookies!)
Never cache auth state — always check on each request
Use requireAuth() in server actions — middleware protects pages, requireAuth protects mutations