11 KiB
Les 18 — Supabase Auth + RLS
Slide Overzicht (Klas A — 3 uur fysiek, demo-driven, laatste les!)
Lesvorm: Tim demonstreert klassikaal. Studenten kijken. Zelf bouwen = huiswerk. Demo-app: Multi-user "Tasks" app met magic-link login + RLS Vervolg op: Les 17 — Externe APIs in diepte Aansluit op: Eindopdracht (thuis)
Slide 1: Title
Les 18 — Supabase Auth + RLS
Visual: "Les 18" BLUE, "Supabase Auth + RLS" BLACK, subtitle "Multi-user apps met per-user data isolation — productie ready"
Slide 2: Terugblik + Curriculum recap
Waar staan we?
18 lessen — wat we hebben gedaan:
- Les 1-10: Foundations (Next.js, Supabase basics, Tailwind, Shadcn, deploy basics, Auth intro)
- Les 11: AI SDK basics + Polderfest
- Les 12: Tool Calling
- Les 13: Agents
- Les 14: RAG + Embeddings
- Les 15: Cursor + Vercel deploy + GitHub Actions CI
- Les 16: MCP servers
- Les 17: Externe APIs in diepte
- Les 18: Vandaag — Supabase Auth + RLS multi-user
Vandaag: alles wat je hebt geleerd, multi-user maken. Klaar voor je eindopdracht.
Slide 3: Planning
Vandaag — 180 minuten
| Onderwerp | Duur |
|---|---|
| Terugblik + waarom auth | 10 min |
| Theorie: Supabase Auth basics | 20 min |
| Theorie: RLS — wat en waarom | 20 min |
| Theorie: Session in Next.js | 15 min |
| Live Demo 1 — Auth setup + magic link | 25 min |
| Live Demo 2 — Middleware + protected routes | 20 min |
| Pauze | 15 min |
| Live Demo 3 — RLS policies multi-user | 30 min |
| Live Demo 4 — Social login (GitHub) | 15 min |
| Eindopdracht recap | 5 min |
| Vragen + afsluiting cyclus | 15 min |
Slide 4: Waarom auth + multi-user
Echte apps hebben users
Wat je niet kunt zonder auth:
- Per-user data (mijn tasks, jouw tasks)
- Privacy (alleen jij ziet je data)
- Audit trail (wie deed wat wanneer)
- Subscriptions (Les 17 — wie betaalde, wie niet)
Auth = 'wie ben jij?' Authz = 'wat mag jij?'
In Supabase: Auth + RLS doen beide. Geïntegreerd, simpel, productie-ready.
Voor je eindopdracht: als je app ÉÉN gebruiker heeft (bv. demo), kun je auth skippen. Maar als je app meerdere users heeft → must have.
Slide 5: Supabase Auth basics
Drie methoden
1. Email + password (klassiek):
- User registreert met email + wachtwoord
- Confirmation email
- Reset-flow voor vergeten wachtwoord
2. Magic link (passwordless):
- User vult email in → krijgt link in mail → klikt → ingelogd
- Geen wachtwoord te onthouden / lekken
- Modern, secure, simpel
3. Social (OAuth):
- "Login met Google", "Login met GitHub"
- User klikt → OAuth flow → Supabase regelt sessie
- Geen account-creation nodig
Voor demo: magic link. Snel, geen wachtwoord-hassle, productie-grade.
await supabase.auth.signInWithOtp({
email: "user@example.com",
});
Slide 6: RLS — wat en waarom
Row Level Security
Het probleem zonder RLS:
-- Anyone with anon key can query everything
SELECT * FROM tasks;
-- Returns ALL tasks of ALL users — disaster
Met RLS:
-- Same query, maar Postgres filtert automatisch:
SELECT * FROM tasks WHERE user_id = auth.uid();
-- Returns alleen JOUW tasks
RLS = filter dat Postgres ALTIJD toepast op queries, ongeacht waar de query vandaan komt (client, server, anonymous, authenticated).
Setup:
alter table tasks enable row level security;
create policy "users see own tasks" on tasks
for select using (auth.uid() = user_id);
create policy "users insert own tasks" on tasks
for insert with check (auth.uid() = user_id);
auth.uid() is Supabase's helper — geeft de ingelogde user ID, of NULL als anonymous.
Slide 7: Session in Next.js
Cookies, middleware, server components
Supabase Auth in Next.js (App Router):
pnpm add @supabase/supabase-js @supabase/ssr
Vier files:
utils/supabase/client.ts— voor client componentsutils/supabase/server.ts— voor server components + actionsutils/supabase/middleware.ts— refresh sessie elke requestmiddleware.ts(root) — gebruikt #3
Waarom de complexiteit:
- Cookies moeten gesynced tussen browser + server
- Sessies verlopen — middleware refreshed
- Voor server-rendering: auth state moet vooraf bekend zijn
Supabase heeft een template voor exact deze setup. Kopiëren werkt, snappen waarom is bonus.
Slide 8: Wat we vandaag bouwen
Multi-user Tasks app
Doel: simpele tasks-app, ieder z'n eigen lijst, geen vermenging.
Tech:
- Next.js 16
- Supabase Auth (magic link + GitHub OAuth)
- Supabase Postgres met RLS
- Tailwind + Shadcn
Features:
/login— magic link form + GitHub button/— task list (alleen ingelogd)- Add / complete / delete task — RLS bepaalt scope
/logout— logout button
Schema:
create table tasks (
id bigserial primary key,
user_id uuid not null references auth.users(id),
text text not null,
done boolean default false,
created_at timestamp default now()
);
Slide 9: LIVE DEMO 1 — Auth setup + magic link
~25 min
Wat ik laat zien:
pnpm create next-app tasks-app + add @supabase/ssr @supabase/supabase-js- Supabase project: Auth → Email → enable Magic Links
utils/supabase/server.ts+client.ts(template van Supabase docs)app/login/page.tsx:"use client"; import { createClient } from "@/utils/supabase/client"; export default function Login() { async function signIn(formData: FormData) { const supabase = createClient(); await supabase.auth.signInWithOtp({ email: formData.get("email") as string, options: { emailRedirectTo: `${location.origin}/auth/callback` }, }); alert("Check je email!"); } return <form action={signIn}><input name="email" /><button>Login</button></form>; }app/auth/callback/route.ts— exchange code voor sessie- Test: email invullen → mail krijgen → klikken → ingelogd
Slide 10: LIVE DEMO 2 — Middleware + protected routes
~20 min
Wat ik laat zien:
middleware.tsroot:
import { type NextRequest } from "next/server";
import { updateSession } from "@/utils/supabase/middleware";
export async function middleware(request: NextRequest) {
return await updateSession(request);
}
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
- Server Component check:
import { createClient } from "@/utils/supabase/server";
import { redirect } from "next/navigation";
export default async function Home() {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) redirect("/login");
return <div>Welcome {user.email}</div>;
}
- Test: niet ingelogd → redirect naar /login. Ingelogd → home page.
Slide 11: Pauze
15 min
Slide 12: LIVE DEMO 3 — RLS policies
~30 min
Wat ik laat zien:
taskstabel + RLS aanzetten:
create table tasks (
id bigserial primary key,
user_id uuid not null references auth.users(id) default auth.uid(),
text text not null,
done boolean default false,
created_at timestamp default now()
);
alter table tasks enable row level security;
create policy "select own" on tasks
for select using (auth.uid() = user_id);
create policy "insert own" on tasks
for insert with check (auth.uid() = user_id);
create policy "update own" on tasks
for update using (auth.uid() = user_id);
create policy "delete own" on tasks
for delete using (auth.uid() = user_id);
- Add task — werkt voor mij, niet voor ander account
- Open tweede browser/incognito met ander account — andere data
- Demo: probeer SQL injection vanaf client — RLS stopt het:
// Probeer: "haal alle users hun tasks op"
const { data } = await supabase.from("tasks").select("*");
// Krijgt alleen JOUW tasks terug — RLS magic
Slide 13: LIVE DEMO 4 — Social login (GitHub)
~15 min
Wat ik laat zien:
- GitHub OAuth App aanmaken (Settings → Developer settings → OAuth Apps)
- Callback URL:
https://your-project.supabase.co/auth/v1/callback - Supabase Dashboard → Auth → Providers → GitHub → enable + client ID/secret
- Login button:
async function signInWithGitHub() {
const supabase = createClient();
await supabase.auth.signInWithOAuth({
provider: "github",
options: { redirectTo: `${location.origin}/auth/callback` },
});
}
- Test: klik → GitHub → authorize → redirect terug → ingelogd
- Database: zelfde RLS werkt — GitHub user heeft eigen
auth.uid()
Slide 14: Eindopdracht recap
Hoe combineer je alles?
Checklist voor je eindopdracht:
- ✓ Next.js + TypeScript + Tailwind (Les 1-10)
- ✓ Supabase Postgres (Les 10)
- ✓ Vercel AI SDK met Tool Calling (Les 11-12)
- ✓ Agent met
stopWhen(Les 13) - ✓ RAG voor documenten (Les 14, optioneel)
- ✓ Cursor + GitHub + Vercel deploy (Les 15)
- ✓ Externe API (Les 17 patterns)
- ✓ Supabase Auth + RLS multi-user (Les 18)
Ideaal eindopdracht-stack:
- Multi-user app waarin elke user eigen data heeft
- AI feature met tool calling of agent
- Minstens 1 externe API integratie
- Deployed op Vercel met preview branches
- Code review via PR's
Tijd: ~40-60 uur thuis. Inleveren via Brightspace + repo URL + live URL.
Slide 15: Afsluiting cyclus
Bedankt en succes!
Wat we samen gedaan hebben:
- 18 lessen, ~54 uur klassikaal
- Van localhost naar productie
- Van simple fetch naar agents + RAG
- Van mock-data naar multi-user productie-apps
Wat je nu zelfstandig kunt:
- Een Next.js app van scratch naar productie
- AI SDK + tool calling + agents
- Externe APIs integreren met OAuth + webhooks
- Multi-user apps met auth + RLS
- Code reviews + CI/CD pipelines
Voor je eindopdracht:
- Werk er gestaag aan (niet laatste week 80 uur)
- Push klein en vaak
- Vraag hulp — Slack, mail, office hours
- Eindopdracht-presentatie volgt na inleveren
Bedankt voor jullie inzet. Veel succes met de eindopdracht.
Slide Summary
| # | Title | Type |
|---|---|---|
| 1 | Title | Opening |
| 2 | Terugblik 18 lessen | Recap |
| 3 | Planning | 180-min |
| 4 | Waarom auth + multi-user | Theorie |
| 5 | Supabase Auth basics | Theorie |
| 6 | RLS — wat en waarom | Theorie |
| 7 | Session in Next.js | Theorie |
| 8 | Wat we bouwen | Intro |
| 9 | DEMO 1 — Auth + magic link | Demo |
| 10 | DEMO 2 — Middleware + protected | Demo |
| 11 | Pauze | Break |
| 12 | DEMO 3 — RLS policies | Demo |
| 13 | DEMO 4 — Social login | Demo |
| 14 | Eindopdracht checklist | Praktijk |
| 15 | Afsluiting cyclus | Closing |
Bronnen
- Supabase Auth docs: https://supabase.com/docs/guides/auth
- Supabase Next.js setup: https://supabase.com/docs/guides/auth/server-side/nextjs
- Supabase Auth UI: https://supabase.com/docs/guides/auth/auth-helpers/auth-ui
- RLS guide: https://supabase.com/docs/guides/database/postgres/row-level-security
- RLS policies in praktijk: https://supabase.com/docs/guides/database/postgres/row-level-security#policies
- Magic links: https://supabase.com/docs/guides/auth/auth-magic-link
- OAuth providers: https://supabase.com/docs/guides/auth/social-login