fix: update lessons

This commit is contained in:
2026-06-03 16:58:25 +02:00
parent eb1ba2e28d
commit a852aa0d52
83 changed files with 16830 additions and 0 deletions

View File

@@ -0,0 +1,407 @@
# 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.
```typescript
await supabase.auth.signInWithOtp({
email: "user@example.com",
});
```
---
## Slide 6: RLS — wat en waarom
### Row Level Security
**Het probleem zonder RLS:**
```sql
-- Anyone with anon key can query everything
SELECT * FROM tasks;
-- Returns ALL tasks of ALL users — disaster
```
**Met RLS:**
```sql
-- 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:**
```sql
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):**
```bash
pnpm add @supabase/supabase-js @supabase/ssr
```
**Vier files:**
1. `utils/supabase/client.ts` — voor client components
2. `utils/supabase/server.ts` — voor server components + actions
3. `utils/supabase/middleware.ts` — refresh sessie elke request
4. `middleware.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:**
```sql
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:**
1. `pnpm create next-app tasks-app + add @supabase/ssr @supabase/supabase-js`
2. Supabase project: Auth → Email → enable Magic Links
3. `utils/supabase/server.ts` + `client.ts` (template van Supabase docs)
4. `app/login/page.tsx`:
```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>;
}
```
5. `app/auth/callback/route.ts` — exchange code voor sessie
6. Test: email invullen → mail krijgen → klikken → ingelogd
---
## Slide 10: LIVE DEMO 2 — Middleware + protected routes
### ~20 min
**Wat ik laat zien:**
1. `middleware.ts` root:
```typescript
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).*)"],
};
```
2. Server Component check:
```tsx
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>;
}
```
3. 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:**
1. `tasks` tabel + RLS aanzetten:
```sql
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);
```
2. Add task — werkt voor mij, niet voor ander account
3. Open tweede browser/incognito met ander account — andere data
4. **Demo: probeer SQL injection vanaf client** — RLS stopt het:
```typescript
// 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:**
1. GitHub OAuth App aanmaken (Settings → Developer settings → OAuth Apps)
2. Callback URL: `https://your-project.supabase.co/auth/v1/callback`
3. Supabase Dashboard → Auth → Providers → GitHub → enable + client ID/secret
4. Login button:
```tsx
async function signInWithGitHub() {
const supabase = createClient();
await supabase.auth.signInWithOAuth({
provider: "github",
options: { redirectTo: `${location.origin}/auth/callback` },
});
}
```
5. Test: klik → GitHub → authorize → redirect terug → ingelogd
6. 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