Files
novi-lessons/Les18-Supabase-Auth-RLS/Les18-Slide-Overzicht.md
2026-06-03 16:58:25 +02:00

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:

  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:

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()
);

~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:
    "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:
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).*)"],
};
  1. 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>;
}
  1. 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:
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);
  1. Add task — werkt voor mij, niet voor ander account
  2. Open tweede browser/incognito met ander account — andere data
  3. 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:

  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:
async function signInWithGitHub() {
  const supabase = createClient();
  await supabase.auth.signInWithOAuth({
    provider: "github",
    options: { redirectTo: `${location.origin}/auth/callback` },
  });
}
  1. Test: klik → GitHub → authorize → redirect terug → ingelogd
  2. 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