When to use it
A new page that only signed-in users, or only admins, may open: an account area, a dashboard, settings.
Rules to keep
src/proxy.tsrefreshes the session and redirects to/loginto make navigation smoother. It is not the access control: the page checks the user itself, and the data is protected by RLS.- Identity and role are resolved on the server. The role comes from
profiles(memberoradmin); never read it from a query string, a cookie or a form field. - Pages that read user data are Server Components. Use a Client Component only for the interactive parts and pass the data to it as props.
Steps
Create
src/app/<route>/page.tsxas an async Server Component and start it likesrc/app/page.tsx:import { redirect } from "next/navigation"; import { createClient } from "@/lib/supabase/server"; export default async function AccountPage() { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) redirect("/login"); // ... }Use
getUser(), which validates the session with Supabase, notgetSession(), which only reads the cookie.For an admin page, read the role after the user check and stop with
notFound(), so the page does not reveal that it exists:const { data: profile } = await supabase .from("profiles") .select("role") .eq("id", user.id) .single(); if (profile?.role !== "admin") notFound();Check the proxy. In this foundation
updateSession(src/lib/supabase/middleware.ts) sends every path except/login,/registerand/authto/loginwhen there is no session, so a new page is already covered. If the file defines a list of protected prefixes, as the products built on this foundation do, add the new prefix to it.Load data with the same
supabaseclient: queries run as the user and RLS applies. If the page needs a new table, follow the playbook "Add a table with RLS" first.Mutations go through a Server Action or a Route Handler that repeats the
getUser()check, and the role check for admin actions: they can be called without opening the page.Link the page from the navigation only for users who can open it. If it opens a new area of the product, describe it in
ARCHITECTURE.md.
Done when
- the verification commands pass;
- without a session the page redirects to
/login; - for an admin page, a
memberaccount gets a 404; - every Server Action or Route Handler used by the page checks the user again.
