# 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 | |
| | | | 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 ? ( | |