How the pieces connect
Supabase Auth issues a JWT access token plus a refresh token. In the App Router, the @supabase/ssr package stores both in cookies so every render context can read the same session. The flow has three touchpoints: middleware runs on each request and calls supabase.auth.getUser() to validate the token against Supabase (not just decode it locally), refreshing it when expired and writing updated cookies onto the response. Server Components create a server client bound to cookies() from next/headers and read the session for data fetching. The browser client, created in a "use client" boundary, handles interactive sign-in and subscribes to onAuthStateChange. Because all three read the same cookie store, server and client stay in sync without you passing the user down as a prop or refetching on the client after navigation.