Files
novi-lessons/Les10-Supabase-Auth/Les10-Slide-Overzicht.md
2026-05-19 18:50:11 +02:00

48 KiB

Les 10 -- Slide-overzicht

Supabase Authenticatie & Row Level Security (15 slides)

Cursus: AI Developer -- NOVI Hogeschool Utrecht Duur: 3 uur (180 minuten) | 09:00 - 12:00 Project: Poll App -- authenticatie toevoegen met Supabase Auth

Voorkennis studenten: Supabase basics uit Les 8 (project setup, database, tabellen). Poll App met Next.js 16, TypeScript, Tailwind CSS. Database met polls en options tabellen. Nog geen authenticatie.


Timing-overzicht

Tijd Duur Onderwerp Slide(s) Vorm
09:00 - 09:05 5 min Titelslide 1 Presentatie
09:05 - 09:10 5 min Planning vandaag 2 Presentatie
09:10 - 09:15 5 min Terugblik Les 8-9 3 Presentatie
09:15 - 09:25 10 min Eindexamenopdracht 4 Presentatie
09:25 - 09:30 5 min Wat is authenticatie? 5 Presentatie
09:30 - 09:40 10 min Supabase Auth -- 3 methodes 6 Presentatie + Demo
09:40 - 09:45 5 min Hoe werkt een sessie? 7 Presentatie
09:45 - 09:55 10 min Auth in Next.js 8 Presentatie
09:55 - 10:00 5 min Row Level Security (RLS) 9 Presentatie
10:00 - 10:15 15 min Pauze 10 Pauze
10:15 - 10:30 15 min Hands-on: Auth opzetten in Supabase 11 Hands-on (ref)
10:30 - 10:55 25 min Hands-on: Login & registratie 12 Hands-on (ref)
10:55 - 11:10 15 min Hands-on: Sessie & beschermde routes 13 Hands-on (ref)
11:10 - 11:25 15 min Hands-on: Basis RLS 14 Hands-on (ref)
11:45 - 12:00 15 min Samenvatting & huiswerk 15 Presentatie

Slide-indeling


Slide 1: Titelslide

Timing: 09:00 - 09:05 (5 min)

Titel: Les 10 -- Supabase Auth & RLS Ondertitel: Authenticatie toevoegen aan de Poll App

+========================================================+
|                                                        |
|            LES 10: SUPABASE AUTH & RLS                 |
|                                                        |
|   Authenticatie toevoegen aan de Poll App              |
|                                                        |
|   Tim -- NOVI Hogeschool Utrecht                       |
|   AI Developer Cursus                                  |
|                                                        |
+========================================================+

Kernpunten:

  • Les 10 van de AI Developer cursus
  • Vandaag draaien we alles om beveiliging: wie mag wat?
  • Supabase Auth + Row Level Security
  • We bouwen verder op de Poll App uit Les 8-9

Spreektekst:

  • "Goedemorgen allemaal, welkom bij Les 10!"
  • "Vandaag gaan we onze Poll App beveiligen met echte authenticatie."
  • "Na vandaag kan niet zomaar iedereen meer polls aanmaken -- je moet ingelogd zijn."
  • "We gebruiken Supabase Auth, wat het hele inlogproces voor ons afhandelt."
  • "En we leren over Row Level Security: beveiliging op database-niveau."

Slide 2: Planning Vandaag

Timing: 09:05 - 09:10 (5 min)

Titel: Planning Vandaag Ondertitel: Wat gaan we doen en leren?

+========================================================+
|  PLANNING VANDAAG                                      |
|                                                        |
|  09:00  Theorie: Auth & RLS concepten                  |
|  09:15  Eindexamenopdracht introductie                 |
|  09:25  Supabase Auth deep dive                        |
|  10:00  -- PAUZE --                                    |
|  10:15  Hands-on: Auth opzetten                        |
|  10:30  Hands-on: Login & registratie                  |
|  10:55  Hands-on: Sessie & beschermde routes           |
|  11:10  Hands-on: Basis RLS                            |
|  11:45  Samenvatting & huiswerk                        |
|                                                        |
|  LEERDOELEN:                                           |
|  [x] Supabase Auth instellen (email/password)          |
|  [x] Login/registratie pagina bouwen                   |
|  [x] Sessie beheren (wie is ingelogd?)                 |
|  [x] Row Level Security policies schrijven             |
+========================================================+

Kernpunten:

  • Eerste helft: theorie over authenticatie, autorisatie, sessies
  • Introductie van de eindexamenopdracht
  • Tweede helft: volledig hands-on, stap voor stap
  • Vier concrete leerdoelen die je vandaag behaalt

Spreektekst:

  • "Dit is de planning voor vandaag. We beginnen met een stuk theorie."
  • "Daarna introduceer ik de eindexamenopdracht -- heel belangrijk."
  • "Na de pauze gaan we volledig hands-on. Ik laat reference slides zien die op het scherm blijven staan terwijl jullie werken."
  • "Aan het einde van vandaag heb je een werkende login, registratie, en beveiligde database."
  • "Vier leerdoelen: Auth instellen, login bouwen, sessie beheren, en RLS schrijven."

Slide 3: Terugblik Les 8-9

Timing: 09:10 - 09:15 (5 min)

Titel: Terugblik Les 8-9 Ondertitel: Waar staan we nu?

+========================================================+
|  TERUGBLIK LES 8-9                                     |
|                                                        |
|  +------------------+    +-------------------------+   |
|  |  SUPABASE        |    |  NEXT.JS APP            |   |
|  |                  |    |                         |   |
|  |  polls           |    |  / (homepage)           |   |
|  |  +----------+    |    |  /polls (lijst)         |   |
|  |  | id       |    |<-->|  /polls/new (aanmaken)  |   |
|  |  | question |    |    |  /polls/[id] (stemmen)  |   |
|  |  +----------+    |    |                         |   |
|  |                  |    |                         |   |
|  |  options         |    |  TypeScript + Tailwind  |   |
|  |  +----------+    |    |                         |   |
|  |  | id       |    |    +-------------------------+   |
|  |  | poll_id  |    |                                  |
|  |  | text     |    |    PROBLEEM:                     |
|  |  | votes    |    |    Iedereen kan alles!           |
|  |  +----------+    |    Geen login nodig              |
|  +------------------+    Geen beveiliging              |
+========================================================+

Kernpunten:

  • Supabase project met polls en options tabellen
  • Next.js app met pagina's voor lijst, aanmaken en stemmen
  • Alles werkt, maar er is geen beveiliging
  • Het probleem: iedereen kan polls aanmaken en data manipuleren

Spreektekst:

  • "Laten we even terugkijken naar waar we staan."
  • "We hebben een werkende Poll App: je kunt polls bekijken, nieuwe polls aanmaken, en stemmen."
  • "De database draait op Supabase met twee tabellen: polls en options."
  • "Maar... er is een groot probleem. Iedereen kan alles doen. Er is geen login."
  • "Als je de Supabase URL en API key kent, kun je direct de database benaderen."
  • "Vandaag gaan we dat oplossen!"

Slide 4: Eindexamenopdracht

Timing: 09:15 - 09:25 (10 min)

Titel: Eindexamenopdracht Ondertitel: Vrije keuze app -- jouw project!

+========================================================+
|  EINDEXAMENOPDRACHT                                    |
|                                                        |
|  Bouw je eigen full-stack applicatie!                   |
|                                                        |
|  VEREISTEN:                                            |
|  +----------------------------------------------------+|
|  | [x] Next.js 16 + TypeScript                        ||
|  | [x] Supabase (database + auth)                     ||
|  | [x] Authenticatie (login/registratie)               ||
|  | [x] Row Level Security (RLS policies)              ||
|  | [x] CRUD operaties (Create, Read, Update, Delete)  ||
|  | [x] Deployed (Vercel + Supabase)                   ||
|  | [x] Nette code (componenten, types, error handling)||
|  +----------------------------------------------------+|
|                                                        |
|  TIJDLIJN:                                             |
|  Les 10 (vandaag)   Introductie + Auth leren           |
|  Les 11-12          Bouwen aan je project              |
|  Les 13             Inleveren + presentatie            |
|                                                        |
|  IDEEN: Todo app, Blog, Recepten, Budget tracker,     |
|         Quiz app, Bookmark manager, Habit tracker...   |
+========================================================+

Kernpunten:

  • Vrije keuze: kies zelf welke app je bouwt
  • Zeven technische vereisten waar je aan moet voldoen
  • Alles wat we in de cursus geleerd hebben komt samen
  • Tijdlijn: 3-4 lessen om te bouwen, daarna inleveren + presentatie
  • Voorbeelden ter inspiratie, maar eigen ideeen zijn welkom

Spreektekst:

  • "Nu iets heel belangrijks: de eindexamenopdracht."
  • "Jullie gaan je eigen full-stack applicatie bouwen. Vrije keuze -- dus kies iets dat je leuk vindt."
  • "Er zijn zeven vereisten. Laten we ze doorlopen."
  • "Next.js 16 met TypeScript -- dat kennen jullie al."
  • "Supabase voor de database EN authenticatie -- dat leren we vandaag."
  • "Je app moet login en registratie hebben, en de database moet beveiligd zijn met RLS."
  • "CRUD: je moet data kunnen aanmaken, lezen, updaten en verwijderen."
  • "De app moet gedeployed zijn op Vercel, zodat ik hem kan bekijken."
  • "En nette code: goede componenten, TypeScript types, error handling."
  • "Qua tijdlijn: vandaag leer je Auth. De komende lessen heb je tijd om te bouwen. En dan presenteren."
  • "Begin alvast na te denken over wat je wilt bouwen. Een todo app, blog, recepten-app, budget tracker... het mag allemaal."

Slide 5: Wat is Authenticatie?

Timing: 09:25 - 09:30 (5 min)

Titel: Wat is Authenticatie? Ondertitel: Auth vs Autorisatie

+========================================================+
|  WAT IS AUTHENTICATIE?                                 |
|                                                        |
|  +------------------------+  +------------------------+|
|  |                        |  |                        ||
|  |      AUTHENTICATIE     |  |      AUTORISATIE       ||
|  |                        |  |                        ||
|  |    "Wie ben je?"       |  |    "Wat mag je?"       ||
|  |                        |  |                        ||
|  |    +--------+          |  |    +--------+          ||
|  |    | SLOT   |          |  |    | SCHILD |          ||
|  |    | [====] |          |  |    |  {X}   |          ||
|  |    +--------+          |  |    +--------+          ||
|  |                        |  |                        ||
|  |  - Inloggen            |  |  - Rechten             ||
|  |  - Email + wachtwoord  |  |  - Rollen (admin/user) ||
|  |  - Identiteit bewijzen |  |  - Wat mag je zien?    ||
|  |                        |  |                        ||
|  +------------------------+  +------------------------+|
|                                                        |
|  VOORBEELD:                                            |
|  Bioscoop: ticket tonen = auth | stoel kiezen = autor. |
|  School:   pasje scannen = auth | lokaal betreden = a. |
+========================================================+

Kernpunten:

  • Authenticatie = wie ben je? Identiteit bewijzen.
  • Autorisatie = wat mag je? Rechten en rollen.
  • Twee aparte concepten die samenwerken
  • Vandaag leren we beide: Auth met Supabase, Autorisatie met RLS

Spreektekst:

  • "Voordat we gaan bouwen, moeten we twee begrippen begrijpen."
  • "Authenticatie: wie ben je? Je bewijst je identiteit. Bijvoorbeeld door in te loggen met email en wachtwoord."
  • "Autorisatie: wat mag je? Welke rechten heb je? Mag je alleen lezen, of ook schrijven?"
  • "Denk aan een bioscoop. Je laat je ticket zien bij de ingang -- dat is authenticatie. Maar je mag alleen in zaal 3 zitten -- dat is autorisatie."
  • "Of school: je scant je pasje -- authenticatie. Maar je mag niet zomaar in elk lokaal -- autorisatie."
  • "Vandaag leren we beide. Supabase Auth regelt de authenticatie. Row Level Security regelt de autorisatie."

Slide 6: Supabase Auth -- 3 Methodes

Timing: 09:30 - 09:40 (10 min)

Titel: Supabase Auth -- 3 Methodes Ondertitel: Hoe kunnen gebruikers inloggen?

+========================================================+
|  SUPABASE AUTH -- 3 METHODES                           |
|                                                        |
|  +----------------+ +----------------+ +--------------+|
|  | EMAIL/PASSWORD | | MAGIC LINK     | | GOOGLE OAUTH ||
|  |                | |                | |              ||
|  | +------------+ | | +------------+ | | +----------+||
|  | | email:     | | | | email:     | | | |  Google  |||
|  | | [........] | | | | [........] | | | |  [G]     |||
|  | | password:  | | | |            | | | |  Login   |||
|  | | [........] | | | | Klik link  | | | +----------+||
|  | | [INLOGGEN] | | | | in je mail | | |            ||
|  | +------------+ | | +------------+ | |              ||
|  |                | |                | |              ||
|  | Klassiek       | | Geen wachtw.  | | Social login ||
|  | Makkelijk te   | | Veilig        | | Makkelijkst  ||
|  | begrijpen      | | Simpel        | | voor users   ||
|  |                | |                | |              ||
|  | WIJ GEBRUIKEN  | | OPTIONEEL     | | NIET VANDAAG ||
|  | DIT VANDAAG    | | (bonus)       | | (complex)    ||
|  +----------------+ +----------------+ +--------------+|
+========================================================+

Kernpunten:

  • Email/Password: klassieke methode, makkelijk te begrijpen, we gebruiken dit vandaag
  • Magic Link: email zonder wachtwoord, gebruiker klikt link in mailbox
  • Google OAuth: social login via Google account, meest gebruiksvriendelijk maar complexer
  • Supabase ondersteunt alle drie out-of-the-box
  • In het Supabase Dashboard kun je providers aan/uitzetten

Spreektekst:

  • "Supabase biedt drie manieren om in te loggen. Laten we ze bekijken."
  • "Nummer 1: email en wachtwoord. De klassieke manier. Je maakt een account aan met je email en een wachtwoord, en daarna log je in. Dit gaan we vandaag gebruiken."
  • "Nummer 2: Magic Link. Je vult alleen je email in, en Supabase stuurt een linkje. Klik erop en je bent ingelogd. Geen wachtwoord nodig. Dit voegen we toe als bonus."
  • "Nummer 3: Google OAuth. De 'Log in met Google' knop die je overal ziet. Heel handig voor gebruikers, maar de setup is complexer. Dat doen we niet vandaag."
  • "Laat me even het Supabase Dashboard laten zien waar je deze providers configureert..."
  • Tim opent Supabase Dashboard > Authentication > Providers en laat de opties zien
  • "Zie je? Email staat standaard aan. Je kunt hier ook Magic Link, Google, GitHub en meer aanzetten."

Slide 7: Hoe Werkt een Sessie?

Timing: 09:40 - 09:45 (5 min)

Titel: Hoe Werkt een Sessie? Ondertitel: Van login tot beveiligde requests

+========================================================+
|  HOE WERKT EEN SESSIE?                                 |
|                                                        |
|  +--------+      +----------+      +-----------+       |
|  | USER   |----->| SUPABASE |----->| JWT TOKEN |       |
|  | login  |      | Auth     |      | (sessie)  |       |
|  +--------+      +----------+      +-----------+       |
|      |                                   |              |
|      |   email + wachtwoord              |              |
|      |                                   v              |
|      |                          +---------------+       |
|      |                          | COOKIE        |       |
|      |                          | (browser)     |       |
|      |                          +---------------+       |
|      |                                   |              |
|      v                                   v              |
|  +---------------------------------------------+       |
|  |  ELKE REQUEST                                |       |
|  |  Browser stuurt cookie automatisch mee       |       |
|  |  Middleware checkt: is de sessie geldig?      |       |
|  |  Zo ja: door naar de pagina                  |       |
|  |  Zo nee: redirect naar /login                |       |
|  +---------------------------------------------+       |
+========================================================+

Kernpunten:

  • User logt in met email + wachtwoord
  • Supabase Auth verifieert en stuurt een JWT token terug
  • JWT wordt opgeslagen als cookie in de browser
  • Bij elke request stuurt de browser de cookie automatisch mee
  • Middleware controleert of de sessie geldig is

Spreektekst:

  • "Hoe werkt een sessie eigenlijk? Laten we het stap voor stap bekijken."
  • "Stap 1: de gebruiker logt in met email en wachtwoord."
  • "Stap 2: Supabase Auth controleert de gegevens. Kloppen ze? Dan krijg je een JWT token terug."
  • "JWT staat voor JSON Web Token. Het is een gecodeerde string die zegt: 'deze gebruiker is ingelogd en dit is hun user ID'."
  • "Stap 3: dat token wordt opgeslagen als cookie in de browser."
  • "Stap 4: bij elke pagina die je bezoekt, stuurt de browser die cookie automatisch mee."
  • "In onze Next.js app hebben we middleware die bij elke request checkt: is er een geldige sessie? Zo nee, dan redirect hij naar /login."
  • "Dit is belangrijk om te begrijpen. Je hoeft het niet zelf te bouwen -- Supabase en de @supabase/ssr package regelen het voor je."

Slide 8: Auth in Next.js

Timing: 09:45 - 09:55 (10 min)

Titel: Auth in Next.js Ondertitel: Architectuur en bestandsstructuur

+========================================================+
|  AUTH IN NEXT.JS -- ARCHITECTUUR                       |
|                                                        |
|  Package: @supabase/ssr                                |
|                                                        |
|  +----------------------------------------------------+|
|  |  BESTANDEN DIE WE GAAN MAKEN:                      ||
|  |                                                    ||
|  |  src/                                              ||
|  |  +-- lib/supabase/                                 ||
|  |  |   +-- client.ts     <-- Browser client          ||
|  |  |   +-- server.ts     <-- Server client           ||
|  |  |                                                 ||
|  |  +-- middleware.ts      <-- Sessie refreshen        ||
|  |  |                                                 ||
|  |  +-- app/                                          ||
|  |      +-- auth/                                     ||
|  |      |   +-- callback/                             ||
|  |      |       +-- route.ts  <-- Auth callback       ||
|  |      +-- login/                                    ||
|  |          +-- page.tsx   <-- Login pagina            ||
|  +----------------------------------------------------+|
|                                                        |
|  BROWSER CLIENT         SERVER CLIENT                  |
|  - Gebruikt in          - Gebruikt in Server           |
|    Client Components      Components & API routes      |
|  - createBrowser...     - createServer...              |
|  - Leest cookies        - Leest EN schrijft cookies    |
+========================================================+

Kernpunten:

  • @supabase/ssr is de package die cookies en sessies afhandelt
  • Browser client: voor Client Components (interactieve UI)
  • Server client: voor Server Components en API routes (data ophalen)
  • Middleware: draait bij elke request, refresht de sessie
  • Auth callback route: verwerkt magic links en OAuth redirects

Spreektekst:

  • "Laten we kijken naar de architectuur. We installeren het package @supabase/ssr."
  • "We maken twee Supabase clients. Waarom twee? Omdat Next.js twee omgevingen heeft."
  • "De browser client gebruik je in Client Components -- dat zijn de interactieve componenten met useState en onClick."
  • "De server client gebruik je in Server Components en API routes -- dat is code die op de server draait."
  • "Het verschil: de browser client kan alleen cookies lezen. De server client kan ze ook schrijven."
  • "Dan hebben we middleware.ts. Die draait bij ELKE request. Zijn taak: de sessie refreshen zodat de gebruiker ingelogd blijft."
  • "En de auth callback route. Die is nodig voor magic links. Als een gebruiker op een magic link klikt, komt hij terug op /auth/callback, en die route wisselt de code om voor een sessie."
  • "Na de pauze gaan we al deze bestanden stap voor stap aanmaken."

Slide 9: Row Level Security (RLS)

Timing: 09:55 - 10:00 (5 min)

Titel: Row Level Security (RLS) Ondertitel: Beveiliging op database-niveau

+========================================================+
|  ROW LEVEL SECURITY (RLS)                              |
|                                                        |
|  ZONDER RLS:                                           |
|  +--------------------------------------------+        |
|  | polls tabel                    GEEN SLOT    |        |
|  | id | question       | created_by            |        |
|  | 1  | Beste taal?    | user_abc   <- leesbaar|        |
|  | 2  | Beste editor?  | user_xyz   <- leesbaar|        |
|  | ** Iedereen kan ALLES lezen, schrijven,     |        |
|  |    updaten en verwijderen **                |        |
|  +--------------------------------------------+        |
|                                                        |
|  MET RLS:                                              |
|  +--------------------------------------------+        |
|  | polls tabel                    [SLOT]       |        |
|  | id | question       | created_by            |        |
|  | 1  | Beste taal?    | user_abc   <- policy! |        |
|  | 2  | Beste editor?  | user_xyz   <- policy! |        |
|  |                                             |        |
|  | POLICIES:                                   |        |
|  | SELECT: iedereen mag lezen                  |        |
|  | INSERT: alleen ingelogde users              |        |
|  | UPDATE: alleen eigen polls                  |        |
|  | DELETE: alleen eigen polls                  |        |
|  +--------------------------------------------+        |
+========================================================+

Kernpunten:

  • Zonder RLS: de API key geeft volledige toegang tot alle data
  • Met RLS: elke query wordt gecheckt tegen policies
  • Policies definieer je per tabel, per operatie (SELECT, INSERT, UPDATE, DELETE)
  • RLS draait op database-niveau -- je kunt het niet omzeilen vanuit de frontend
  • Dit is de autorisatie-laag die we eerder bespraken

Spreektekst:

  • "Nu het laatste theoretische concept: Row Level Security, oftewel RLS."
  • "Onthoud: onze Supabase API key staat in de frontend code. Iedereen kan die zien."
  • "Zonder RLS kan iemand met die key ALLES doen: lezen, schrijven, verwijderen. Dat is een groot beveiligingsprobleem."
  • "Met RLS zet je een slot op je tabellen. Je definieert policies: regels die zeggen wie wat mag."
  • "Bijvoorbeeld: iedereen mag polls LEZEN, maar alleen ingelogde users mogen polls AANMAKEN."
  • "Of: je mag alleen je EIGEN polls updaten of verwijderen."
  • "Het mooie van RLS is dat het op database-niveau draait. Zelfs als iemand direct de API aanroept, worden de policies gecontroleerd."
  • "Na de pauze gaan we dit ook daadwerkelijk instellen."

Slide 10: Pauze

Timing: 10:00 - 10:15 (15 min)

Titel: Pauze Ondertitel: 15 minuten

+========================================================+
|                                                        |
|                                                        |
|                      PAUZE                             |
|                                                        |
|                   15 minuten                           |
|                                                        |
|              10:00 -- 10:15                             |
|                                                        |
|                                                        |
|   Tip: Denk alvast na over je eindexamenopdracht!      |
|   Welke app wil je bouwen?                             |
|                                                        |
|                                                        |
+========================================================+

Kernpunten:

  • 15 minuten pauze
  • Studenten kunnen alvast nadenken over hun eindexamenopdracht
  • Na de pauze: hands-on, dus zorg dat je laptop klaar staat

Spreektekst:

  • "Oké, tijd voor pauze! 15 minuten."
  • "Denk alvast na over wat je wilt bouwen voor je eindexamenopdracht."
  • "Na de pauze gaan we direct aan de slag. Zorg dat je Cursor open hebt en je Supabase project klaarstaat."
  • "Tot zo!"

Slide 11: Hands-on -- Auth Opzetten in Supabase (REFERENCE SLIDE)

Timing: 10:15 - 10:30 (15 min)

Titel: Hands-on -- Auth Opzetten Ondertitel: REFERENCE SLIDE -- blijft op het scherm

+========================================================+
|  HANDS-ON: AUTH OPZETTEN                    [REF]      |
|                                                        |
|  STAP 1: Starter project                               |
|  $ Pak de starter zip uit en open in Cursor            |
|  $ npm install                                         |
|                                                        |
|  STAP 2: Environment variabelen                        |
|  Maak .env.local:                                      |
|  NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co      |
|  NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...             |
|                                                        |
|  STAP 3: Packages installeren                          |
|  $ npm install @supabase/ssr @supabase/supabase-js     |
|                                                        |
|  STAP 4: Browser client (src/lib/supabase/client.ts)   |
|  import { createBrowserClient } from '@supabase/ssr'   |
|  export function createClient() {                      |
|    return createBrowserClient(                         |
|      process.env.NEXT_PUBLIC_SUPABASE_URL!,            |
|      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!        |
|    )                                                   |
|  }                                                     |
|                                                        |
|  STAP 5: Server client (src/lib/supabase/server.ts)    |
|  import { createServerClient } from '@supabase/ssr'    |
|  import { cookies } from 'next/headers'                |
|  export async function createClient() {                |
|    const cookieStore = await cookies()                 |
|    return createServerClient(                          |
|      process.env.NEXT_PUBLIC_SUPABASE_URL!,            |
|      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,       |
|      { cookies: {                                      |
|          getAll() { return cookieStore.getAll() },     |
|          setAll(cookiesToSet) {                         |
|            cookiesToSet.forEach(({ name, value, opts })|
|              => cookieStore.set(name, value, opts))    |
|          },                                            |
|      }}                                                |
|    )                                                   |
|  }                                                     |
|                                                        |
|  STAP 6: Middleware (src/middleware.ts)                 |
|  import { createServerClient } from '@supabase/ssr'    |
|  import { NextResponse, type NextRequest } from 'next' |
|  export async function middleware(request: NextRequest) |
|    // Refresh sessie bij elke request                  |
|    // Redirect naar /login als niet ingelogd           |
|                                                        |
|  STAP 7: Auth callback (src/app/auth/callback/route.ts)|
|  // Verwerkt magic link codes                          |
|  // Wisselt code om voor sessie                        |
|                                                        |
|  STAP 8: Supabase Dashboard                            |
|  Authentication > Providers > Email aanvinken          |
+========================================================+

Kernpunten:

  • Stap 1-2: Project openen en environment variabelen instellen
  • Stap 3: Twee packages installeren: @supabase/ssr en @supabase/supabase-js
  • Stap 4: Browser client voor Client Components
  • Stap 5: Server client met cookie-handling voor Server Components
  • Stap 6: Middleware die sessie refresht en ongeautoriseerde users redirect
  • Stap 7: Auth callback route voor magic links
  • Stap 8: Email provider aanzetten in Supabase Dashboard

Spreektekst:

  • "Oké, we gaan aan de slag! Deze slide blijft op het scherm. Volg de stappen."
  • "Stap 1: pak de starter zip uit die ik gestuurd heb, en open het project in Cursor. Doe npm install."
  • "Stap 2: maak een .env.local bestand. Kopieer je Supabase URL en anon key uit het dashboard."
  • "Stap 3: installeer de twee packages: @supabase/ssr en @supabase/supabase-js."
  • "Stap 4: maak de browser client aan. Dit is heel simpel -- je roept createBrowserClient aan met je URL en key."
  • "Stap 5: de server client is iets complexer. Die heeft cookie-handling nodig. Kopieer de code van de slide."
  • "Stap 6: de middleware. Die zorgt dat de sessie bij elke request ververst wordt. En hij redirect naar /login als je niet ingelogd bent."
  • "Stap 7: de auth callback route. Die heb je nodig voor magic links."
  • "Stap 8: ga naar je Supabase Dashboard, Authentication, Providers, en zet Email aan."
  • "Neem de tijd, volg het stap voor stap. Ik loop rond om te helpen."

Slide 12: Hands-on -- Login & Registratie (REFERENCE SLIDE)

Timing: 10:30 - 10:55 (25 min)

Titel: Hands-on -- Login & Registratie Ondertitel: REFERENCE SLIDE -- blijft op het scherm

+========================================================+
|  HANDS-ON: LOGIN & REGISTRATIE              [REF]      |
|                                                        |
|  STAP 1: Maak src/app/login/page.tsx                   |
|  'use client'                                          |
|  import { useState } from 'react'                      |
|  import { createClient } from '@/lib/supabase/client'  |
|  import { useRouter } from 'next/navigation'           |
|                                                        |
|  STAP 2: State                                         |
|  const [email, setEmail] = useState('')                |
|  const [password, setPassword] = useState('')          |
|  const [loading, setLoading] = useState(false)         |
|  const [message, setMessage] = useState('')            |
|  const router = useRouter()                            |
|  const supabase = createClient()                       |
|                                                        |
|  STAP 3: handleSignUp functie                          |
|  async function handleSignUp() {                       |
|    setLoading(true)                                    |
|    const { error } = await supabase.auth.signUp({      |
|      email, password                                   |
|    })                                                  |
|    if (error) setMessage(error.message)                |
|    else setMessage('Check je email voor confirmatie!') |
|    setLoading(false)                                   |
|  }                                                     |
|                                                        |
|  STAP 4: handleSignIn functie                          |
|  async function handleSignIn() {                       |
|    setLoading(true)                                    |
|    const { error } = await                             |
|      supabase.auth.signInWithPassword({                |
|        email, password                                 |
|      })                                                |
|    if (error) setMessage(error.message)                |
|    else router.push('/')                               |
|    setLoading(false)                                   |
|  }                                                     |
|                                                        |
|  STAP 5: handleMagicLink functie (bonus)               |
|  async function handleMagicLink() {                    |
|    setLoading(true)                                    |
|    const { error } = await                             |
|      supabase.auth.signInWithOtp({ email })            |
|    if (error) setMessage(error.message)                |
|    else setMessage('Check je email voor de link!')     |
|    setLoading(false)                                   |
|  }                                                     |
|                                                        |
|  STAP 6: Formulier JSX                                 |
|  <form>                                                |
|    <input type="email" value={email}                   |
|           onChange={e => setEmail(e.target.value)} />   |
|    <input type="password" value={password}             |
|           onChange={e => setPassword(e.target.value)} />|
|    <button onClick={handleSignIn}>Inloggen</button>    |
|    <button onClick={handleSignUp}>Registreren</button> |
|    <button onClick={handleMagicLink}>Magic Link</but.> |
|    {message && <p>{message}</p>}                       |
|  </form>                                               |
|                                                        |
|  STAP 7: Error handling & loading states               |
|  - disabled={loading} op alle buttons                  |
|  - Loading tekst: "Even geduld..."                     |
|  - Error message tonen in rode tekst                   |
|                                                        |
|  STAP 8: Testen                                        |
|  - Registreer een account (check Supabase Dashboard)   |
|  - Log in met dat account                              |
|  - Probeer magic link (check je email)                 |
+========================================================+

Kernpunten:

  • Login pagina als Client Component ('use client')
  • State voor email, password, loading en foutmeldingen
  • signUp(): registratie, stuurt een bevestigingsmail
  • signInWithPassword(): inloggen met email + wachtwoord
  • signInWithOtp(): magic link versturen (bonus)
  • Formulier met drie buttons: inloggen, registreren, magic link
  • Na succesvolle login: redirect naar homepage
  • Testen: registreer, log in, check Supabase Dashboard

Spreektekst:

  • "Nu gaan we de login pagina bouwen. Dit wordt een Client Component omdat we interactie nodig hebben."
  • "Stap 1: maak het bestand src/app/login/page.tsx aan."
  • "Stap 2: we hebben vier stukken state nodig: email, password, loading, en een message voor foutmeldingen."
  • "Stap 3: de handleSignUp functie. Die roept supabase.auth.signUp aan met de email en het wachtwoord. Als het lukt, krijgt de gebruiker een bevestigingsmail."
  • "Stap 4: handleSignIn. Dit is het echte inloggen. signInWithPassword. Als het lukt, redirect je naar de homepage."
  • "Stap 5: de magic link als bonus. signInWithOtp -- je geeft alleen de email mee, geen wachtwoord."
  • "Stap 6: het formulier. Twee input velden en drie buttons. Simpel."
  • "Stap 7: vergeet de error handling niet! Disable de buttons als het laden is, en toon foutmeldingen."
  • "Stap 8: testen! Registreer een account en check in het Supabase Dashboard of de user verschijnt onder Authentication > Users."
  • "Dit is de meest uitgebreide stap, dus neem je tijd. Ik loop rond."

Slide 13: Hands-on -- Sessie & Beschermde Routes (REFERENCE SLIDE)

Timing: 10:55 - 11:10 (15 min)

Titel: Hands-on -- Sessie & Beschermde Routes Ondertitel: REFERENCE SLIDE -- blijft op het scherm

+========================================================+
|  HANDS-ON: SESSIE & BESCHERMDE ROUTES       [REF]      |
|                                                        |
|  STAP 1: User ophalen in layout/navbar                 |
|  // In een Server Component:                           |
|  import { createClient } from '@/lib/supabase/server'  |
|                                                        |
|  const supabase = await createClient()                 |
|  const { data: { user } } = await                      |
|    supabase.auth.getUser()                             |
|                                                        |
|  STAP 2: Conditional rendering                         |
|  {user ? (                                             |
|    <div>                                               |
|      <span>{user.email}</span>                         |
|      <LogoutButton />                                  |
|    </div>                                              |
|  ) : (                                                 |
|    <a href="/login">Inloggen</a>                       |
|  )}                                                    |
|                                                        |
|  STAP 3: LogoutButton component (Client Component)     |
|  'use client'                                          |
|  import { createClient } from '@/lib/supabase/client'  |
|  import { useRouter } from 'next/navigation'           |
|                                                        |
|  export function LogoutButton() {                      |
|    const router = useRouter()                          |
|    const supabase = createClient()                     |
|                                                        |
|    async function handleSignOut() {                    |
|      await supabase.auth.signOut()                     |
|      router.push('/login')                             |
|    }                                                   |
|                                                        |
|    return (                                            |
|      <button onClick={handleSignOut}>Uitloggen</button>|
|    )                                                   |
|  }                                                     |
|                                                        |
|  STAP 4: Redirect na logout naar /login                |
|  router.push('/login') in handleSignOut                |
|                                                        |
|  STAP 5: Testen                                        |
|  [x] Ga naar / zonder login -> redirect naar /login    |
|  [x] Log in -> je ziet je email in de navbar           |
|  [x] Klik uitloggen -> redirect naar /login            |
|  [x] Na uitloggen kun je niet bij / komen              |
+========================================================+

Kernpunten:

  • getUser() op de server om de huidige gebruiker op te halen
  • Conditional rendering: toon email + logout als ingelogd, anders login-link
  • LogoutButton is een Client Component (interactief)
  • signOut() verwijdert de sessie, daarna redirect naar /login
  • Middleware handelt de bescherming af: geen sessie = redirect naar /login

Spreektekst:

  • "Nu gaan we de sessie zichtbaar maken in de UI."
  • "Stap 1: in je layout of navbar haal je de user op. Let op: dit is een Server Component, dus gebruik de server client."
  • "supabase.auth.getUser() geeft de huidige ingelogde user terug, of null als niemand ingelogd is."
  • "Stap 2: conditional rendering. Als er een user is, toon de email en een logout button. Anders toon een link naar /login."
  • "Stap 3: de LogoutButton moet een Client Component zijn, want hij heeft een onClick nodig."
  • "De handleSignOut functie roept supabase.auth.signOut() aan. Dat verwijdert de sessie cookie."
  • "Stap 4: na het uitloggen stuur je de gebruiker terug naar /login met router.push."
  • "Stap 5: testen! Open een incognito venster en ga naar de homepage. Je zou geredirect moeten worden naar /login."
  • "Log in, en je ziet je email in de navbar. Klik uitloggen, en je gaat terug naar /login."
  • "Als dit allemaal werkt, heb je een werkend auth-systeem!"

Slide 14: Hands-on -- Basis RLS (REFERENCE SLIDE)

Timing: 11:10 - 11:25 (15 min)

Titel: Hands-on -- Basis RLS Ondertitel: REFERENCE SLIDE -- blijft op het scherm

+========================================================+
|  HANDS-ON: BASIS RLS                        [REF]      |
|                                                        |
|  Ga naar Supabase Dashboard > SQL Editor               |
|                                                        |
|  STAP 1: Enable RLS op polls                           |
|  ALTER TABLE polls ENABLE ROW LEVEL SECURITY;          |
|                                                        |
|  STAP 2: Enable RLS op options                         |
|  ALTER TABLE options ENABLE ROW LEVEL SECURITY;        |
|                                                        |
|  STAP 3: Iedereen mag polls LEZEN                      |
|  CREATE POLICY "Iedereen mag polls lezen"              |
|  ON polls FOR SELECT                                   |
|  TO public                                             |
|  USING (true);                                         |
|                                                        |
|  STAP 4: Alleen ingelogde users mogen polls AANMAKEN   |
|  CREATE POLICY "Ingelogde users mogen polls aanmaken"  |
|  ON polls FOR INSERT                                   |
|  TO authenticated                                      |
|  WITH CHECK (true);                                    |
|                                                        |
|  STAP 5: Iedereen mag options LEZEN                    |
|  CREATE POLICY "Iedereen mag options lezen"            |
|  ON options FOR SELECT                                 |
|  TO public                                             |
|  USING (true);                                         |
|                                                        |
|  STAP 6: Ingelogde users mogen options AANMAKEN        |
|  CREATE POLICY "Ingelogde users mogen options maken"   |
|  ON options FOR INSERT                                 |
|  TO authenticated                                      |
|  WITH CHECK (true);                                    |
|                                                        |
|  STAP 7: Ingelogde users mogen stemmen (UPDATE)        |
|  CREATE POLICY "Ingelogde users mogen stemmen"         |
|  ON options FOR UPDATE                                 |
|  TO authenticated                                      |
|  USING (true)                                          |
|  WITH CHECK (true);                                    |
|                                                        |
|  STAP 8: Testen -- app werkt als ingelogd             |
|  [x] Polls laden nog steeds                            |
|  [x] Je kunt nog steeds een poll aanmaken              |
|  [x] Je kunt nog steeds stemmen                        |
|                                                        |
|  STAP 9: Testen -- zonder login geen schrijfrechten    |
|  [x] Polls zijn zichtbaar (SELECT = public)            |
|  [x] Poll aanmaken FAALT (INSERT = authenticated)      |
|  [x] Stemmen FAALT (UPDATE = authenticated)            |
+========================================================+

Kernpunten:

  • RLS moet per tabel ingeschakeld worden met ALTER TABLE ... ENABLE ROW LEVEL SECURITY
  • Na het inschakelen van RLS is ALLES geblokkeerd totdat je policies aanmaakt
  • TO public = iedereen (ook niet ingelogd)
  • TO authenticated = alleen ingelogde users
  • USING (true) = geen extra voorwaarden (alle rijen)
  • WITH CHECK (true) = geen extra voorwaarden bij schrijven
  • Altijd testen: werkt het als ingelogd? Faalt het zonder login?

Spreektekst:

  • "De laatste stap: Row Level Security! Open de SQL Editor in je Supabase Dashboard."
  • "Stap 1 en 2: enable RLS op beide tabellen. LET OP: zodra je dit doet, is alles geblokkeerd. Je app zal even niet werken totdat je policies toevoegt."
  • "Stap 3: de eerste policy. Iedereen mag polls lezen. FOR SELECT, TO public, USING true. Public betekent iedereen, ook niet-ingelogde gebruikers."
  • "Stap 4: alleen ingelogde users mogen polls aanmaken. FOR INSERT, TO authenticated. Authenticated betekent: je moet een geldige sessie hebben."
  • "Stap 5 en 6: hetzelfde voor de options tabel. Iedereen mag lezen, alleen ingelogde users mogen aanmaken."
  • "Stap 7: ingelogde users mogen stemmen. Stemmen is een UPDATE operatie -- je update het votes veld."
  • "Stap 8: test als ingelogde user. Alles zou moeten werken zoals voorheen."
  • "Stap 9: test zonder login. Open een incognito venster. Polls zijn zichtbaar -- want SELECT is public. Maar een poll aanmaken of stemmen? Dat faalt nu. Precies wat we willen!"
  • "Gefeliciteerd! Je database is nu beveiligd."

Slide 15: Samenvatting & Huiswerk

Timing: 11:45 - 12:00 (15 min)

Titel: Samenvatting & Huiswerk Ondertitel: Wat hebben we geleerd?

+========================================================+
|  SAMENVATTING                                          |
|                                                        |
|  5 KEY TAKEAWAYS:                                      |
|                                                        |
|  1. Authenticatie = wie ben je?                         |
|     Autorisatie = wat mag je?                           |
|                                                        |
|  2. Supabase Auth regelt login/registratie              |
|     Email/password, magic link, of OAuth               |
|                                                        |
|  3. Sessies werken via JWT tokens in cookies            |
|     Middleware refresht de sessie automatisch           |
|                                                        |
|  4. Twee clients: browser (client) + server             |
|     @supabase/ssr handelt cookies af                   |
|                                                        |
|  5. RLS beveiligt je database met policies              |
|     public = iedereen | authenticated = ingelogd       |
|                                                        |
|  ---------------------------------------------------- |
|                                                        |
|  HUISWERK:                                             |
|  [1] Bedenk je eindexamenopdracht (welke app?)         |
|  [2] Maak een lijstje van je tabellen + kolommen       |
|  [3] Bedenk welke RLS policies je nodig hebt           |
|  [4] Optioneel: voeg user_id kolom toe aan polls       |
|      en maak een policy: alleen eigen polls deleten    |
|                                                        |
|  VOLGENDE LES:                                         |
|  Bouwen aan je eindexamenopdracht!                     |
+========================================================+

Kernpunten:

  • Vijf key takeaways die alles van vandaag samenvatten
  • Authenticatie vs autorisatie: twee aparte concepten
  • Supabase Auth: drie methodes, wij gebruikten email/password
  • Sessies: JWT tokens, cookies, middleware
  • Twee Supabase clients: browser en server
  • RLS: policies per tabel, per operatie, public vs authenticated
  • Huiswerk: eindexamenopdracht bedenken en tabellen plannen

Spreektekst:

  • "Laten we samenvatten wat we vandaag geleerd hebben."
  • "Takeaway 1: authenticatie is wie ben je, autorisatie is wat mag je. Twee aparte dingen."
  • "Takeaway 2: Supabase Auth regelt de authenticatie voor ons. We gebruikten email en wachtwoord, en als bonus magic links."
  • "Takeaway 3: sessies werken via JWT tokens die in cookies worden opgeslagen. De middleware refresht ze automatisch."
  • "Takeaway 4: in Next.js heb je twee Supabase clients nodig. Een voor de browser en een voor de server. Het @supabase/ssr package maakt dit mogelijk."
  • "Takeaway 5: RLS beveiligt je database met policies. Public is voor iedereen, authenticated is alleen voor ingelogde users."
  • "Nu het huiswerk. Dit is belangrijk voor de eindexamenopdracht."
  • "Nummer 1: bedenk welke app je wilt bouwen. Kies iets dat je leuk vindt en dat haalbaar is."
  • "Nummer 2: maak een lijstje van de tabellen die je nodig hebt en welke kolommen ze hebben."
  • "Nummer 3: bedenk welke RLS policies je nodig hebt. Wie mag wat lezen en schrijven?"
  • "Nummer 4 is optioneel: voeg een user_id kolom toe aan de polls tabel, zodat je kunt bijhouden wie een poll heeft aangemaakt. Dan kun je een policy maken dat je alleen je eigen polls mag verwijderen."
  • "Volgende les gaan we bouwen aan jullie eindexamenopdracht. Zorg dat je een plan hebt!"
  • "Goed gedaan vandaag. Vragen? Anders zie ik jullie volgende week!"