# Les 10 Huiswerk: Supabase Auth Uitbreiden & Eindopdracht Brainstorm

**Vak:** AI-Assisted Development  
**Opleiding:** NOVI Hogeschool Utrecht  
**Deadline:** Voor de volgende les

---

## Overzicht

In les 10 hebben we Supabase Auth toegevoegd aan onze Poll App: email/password login, magic links en basis Row Level Security (RLS). In dit huiswerk ga je de authenticatie uitbreiden met Google OAuth, polls koppelen aan gebruikers, en nadenken over je eindexamenopdracht.

**Wat je al hebt na de les:**
- Supabase project met Auth ingeschakeld
- Email/password registratie en login
- Magic link login
- Basis RLS policies op de `polls` tabel
- Login- en registratiepagina in je app

---

## Opdrachten

### Opdracht 1: Google OAuth toevoegen

Voeg Google OAuth toe als derde inlogmethode naast email/password en magic link.

**Stappen:**

1. Maak een Google Cloud project aan (zie Appendix A)
2. Configureer OAuth credentials in Google Cloud Console
3. Voeg de credentials toe in je Supabase dashboard
4. Bouw een "Inloggen met Google" knop in je app

**Checklist:**

- [ ] Google Cloud project aangemaakt
- [ ] OAuth 2.0 Client ID en Client Secret gegenereerd
- [ ] Redirect URL correct ingesteld in Google Cloud Console
- [ ] Google provider ingeschakeld in Supabase Auth settings
- [ ] Google login knop toegevoegd aan je login pagina
- [ ] Google OAuth werkend in je app (je kunt inloggen met je Google account)

**Code voorbeeld - Google login knop:**

```javascript
async function signInWithGoogle() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'google',
    options: {
      redirectTo: window.location.origin
    }
  })

  if (error) {
    console.error('Google login error:', error.message)
  }
}
```

```html
<button onclick="signInWithGoogle()" class="google-login-btn">
  Inloggen met Google
</button>
```

**Styling tip:** Gebruik de officiële Google kleuren en logo voor je knop. Google heeft richtlijnen voor hoe hun login knop eruit moet zien: wit of blauw met het Google "G" logo.

---

### Opdracht 2: User-gekoppelde polls

Koppel elke poll aan de gebruiker die hem heeft aangemaakt. Zo kun je laten zien wie een poll heeft gemaakt en ervoor zorgen dat alleen de eigenaar zijn eigen polls kan bewerken of verwijderen.

**Stappen:**

1. Voeg een `user_id` kolom toe aan de `polls` tabel
2. Werk de RLS policies bij zodat gebruikers alleen hun eigen polls kunnen bewerken/verwijderen
3. Update je app zodat bij het aanmaken van een poll automatisch de `user_id` wordt meegegeven
4. Toon in de app wie elke poll heeft aangemaakt

**Checklist:**

- [ ] `user_id` kolom toegevoegd aan `polls` tabel (uuid, references auth.users)
- [ ] Bestaande polls een `user_id` gegeven (mag je eigen user id zijn)
- [ ] RLS policy: iedereen kan polls lezen (SELECT)
- [ ] RLS policy: ingelogde gebruikers kunnen polls aanmaken (INSERT)
- [ ] RLS policy: alleen de eigenaar kan zijn poll bewerken (UPDATE)
- [ ] RLS policy: alleen de eigenaar kan zijn poll verwijderen (DELETE)
- [ ] App stuurt `user_id` mee bij het aanmaken van een poll
- [ ] App toont wie elke poll heeft aangemaakt

**SQL voor de kolom en policies:** zie Appendix B.

**Code voorbeeld - Poll aanmaken met user_id:**

```javascript
async function createPoll(question, options) {
  const { data: { user } } = await supabase.auth.getUser()

  const { data, error } = await supabase
    .from('polls')
    .insert({
      question: question,
      options: options,
      user_id: user.id
    })
    .select()

  if (error) {
    console.error('Error creating poll:', error.message)
    return null
  }

  return data
}
```

**Code voorbeeld - Polls ophalen met user info:**

```javascript
async function getPolls() {
  const { data, error } = await supabase
    .from('polls')
    .select('*')
    .order('created_at', { ascending: false })

  if (error) {
    console.error('Error fetching polls:', error.message)
    return []
  }

  return data
}
```

**UI tip:** Toon de email van de maker onder elke poll. Je kunt `user_id` gebruiken om de gebruikersinfo op te halen, of je slaat de email direct op bij de poll.

---

### Opdracht 3: Eindexamenopdracht brainstorm

De eindexamenopdracht is een zelfgekozen app die je bouwt met Supabase en AI-assisted development. Begin nu met nadenken over wat je wilt bouwen.

**Schrijf het volgende op (geen code nodig):**

1. **App naam** - Hoe heet je app?
2. **Beschrijving** - Wat doet je app? (2-3 zinnen)
3. **3 hoofdfuncties** - Wat zijn de drie belangrijkste features?
4. **Supabase features** - Welke Supabase onderdelen ga je gebruiken?
   - Database (welke tabellen?)
   - Auth (welke methoden?)
   - Storage (voor wat?)
   - RLS (welke regels?)
   - Realtime (waarvoor?)

**Checklist:**

- [ ] App naam gekozen
- [ ] Beschrijving geschreven (2-3 zinnen)
- [ ] 3 hoofdfuncties beschreven
- [ ] Supabase features opgelijst
- [ ] Eindexamenopdracht idee uitgeschreven

**Voorbeeld format:**

```
App naam: StudyBuddy
Beschrijving: Een app waar studenten samen kunnen leren door
  flashcards te maken en te delen. Gebruikers kunnen elkaars
  kaarten beoordelen en favorieten opslaan.

Hoofdfuncties:
1. Flashcards aanmaken met vraag/antwoord
2. Kaarten delen met andere gebruikers
3. Quiz-modus om jezelf te testen

Supabase features:
- Database: tabellen voor users, flashcards, favorites, scores
- Auth: email/password + Google OAuth
- Storage: afbeeldingen bij flashcards
- RLS: eigen kaarten bewerken, gedeelde kaarten alleen lezen
- Realtime: live quiz-sessies met meerdere spelers
```

---

## Wat lever je in?

1. **GitHub repository link** (public, of nodig Tim uit als collaborator)
2. **Korte reflectie** (150 woorden): wat ging goed, wat was lastig, wat wil je bouwen voor de eindopdracht?
3. **Screenshots van:**
   - Google login werkend in je app
   - Polls met user info zichtbaar
   - RLS test (bijv. probeer een poll van iemand anders te verwijderen)
4. **Eindexamenopdracht brainstorm** (mag in een apart bestand of in je README)

---

## Tips

- **Google OAuth testen:** Je kunt je eigen Gmail account gebruiken om te testen. Je hoeft geen "productie" goedkeuring van Google te hebben voor development.
- **RLS testen:** Open twee browsers (bijv. Chrome en Firefox) met verschillende accounts om te testen of je echt alleen je eigen polls kunt bewerken.
- **Supabase Dashboard:** Gebruik de SQL Editor in het Supabase dashboard om je policies te testen voordat je ze in je app gebruikt.
- **AI gebruiken:** Gebruik Claude of ChatGPT om je te helpen met SQL queries en RLS policies. Geef de AI je huidige tabelstructuur en vraag om hulp.
- **Eindopdracht:** Kies iets dat je zelf leuk vindt om te bouwen. Motivatie is de belangrijkste factor voor een goed eindproject.
- **Foutmeldingen:** Als je RLS errors krijgt zoals "new row violates row-level security policy", controleer dan of je policies correct zijn ingesteld (zie Appendix C).

---

## Appendix A: Google OAuth Setup stap-voor-stap

### Stap 1: Google Cloud Project aanmaken

1. Ga naar [Google Cloud Console](https://console.cloud.google.com/)
2. Klik op het project dropdown menu bovenaan
3. Klik op **"New Project"**
4. Geef je project een naam (bijv. "Poll App NOVI")
5. Klik op **"Create"**

### Stap 2: OAuth Consent Screen configureren

1. Ga naar **APIs & Services > OAuth consent screen**
2. Kies **"External"** als user type
3. Vul in:
   - **App name:** Poll App
   - **User support email:** jouw email
   - **Developer contact:** jouw email
4. Klik op **"Save and Continue"**
5. Bij Scopes: klik op **"Save and Continue"** (standaard scopes zijn voldoende)
6. Bij Test users: voeg je eigen Gmail adres toe
7. Klik op **"Save and Continue"**

### Stap 3: OAuth Credentials aanmaken

1. Ga naar **APIs & Services > Credentials**
2. Klik op **"+ Create Credentials" > "OAuth client ID"**
3. Application type: **"Web application"**
4. Naam: "Poll App Supabase"
5. Bij **Authorized redirect URIs**, voeg toe:
   ```
   https://<jouw-project-id>.supabase.co/auth/v1/callback
   ```
   (Vervang `<jouw-project-id>` met je Supabase project ID)
6. Klik op **"Create"**
7. Kopieer de **Client ID** en **Client Secret**

### Stap 4: Supabase configureren

1. Ga naar je Supabase dashboard
2. Ga naar **Authentication > Providers**
3. Zoek **Google** in de lijst en klik erop
4. Zet de toggle op **Enabled**
5. Plak je **Client ID** en **Client Secret**
6. Klik op **"Save"**

### Stap 5: Code toevoegen

```javascript
// Google login functie
async function signInWithGoogle() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'google',
    options: {
      redirectTo: window.location.origin
    }
  })

  if (error) {
    console.error('Google login error:', error.message)
    alert('Er ging iets mis met Google login. Probeer het opnieuw.')
  }
}
```

```html
<!-- Voeg toe aan je login pagina -->
<div class="divider">of</div>

<button onclick="signInWithGoogle()" class="btn-google">
  <img src="https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/google.svg"
       alt="Google logo" width="20" height="20">
  Inloggen met Google
</button>
```

```css
.btn-google {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  background: white;
  border: 1px solid #dadce0;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  width: 100%;
  justify-content: center;
}

.btn-google:hover {
  background: #f7f8f8;
}

.divider {
  text-align: center;
  margin: 20px 0;
  color: #666;
}
```

---

## Appendix B: SQL voor user_id kolom en updated policies

### Stap 1: user_id kolom toevoegen

```sql
-- Voeg user_id kolom toe aan polls tabel
ALTER TABLE polls
ADD COLUMN user_id UUID REFERENCES auth.users(id);

-- Optioneel: geef bestaande polls jouw user_id
-- Vervang 'jouw-user-id-hier' met je echte user ID uit Supabase Auth
UPDATE polls
SET user_id = 'jouw-user-id-hier'
WHERE user_id IS NULL;

-- Maak user_id verplicht voor nieuwe polls
ALTER TABLE polls
ALTER COLUMN user_id SET NOT NULL;
```

**Je user ID vinden:** Ga naar Supabase Dashboard > Authentication > Users en kopieer je ID.

### Stap 2: Bestaande policies verwijderen

```sql
-- Verwijder oude policies (pas de namen aan naar jouw policy namen)
DROP POLICY IF EXISTS "Allow all select" ON polls;
DROP POLICY IF EXISTS "Allow all insert" ON polls;
DROP POLICY IF EXISTS "Allow all update" ON polls;
DROP POLICY IF EXISTS "Allow all delete" ON polls;
```

### Stap 3: Nieuwe RLS policies aanmaken

```sql
-- Iedereen (ook niet-ingelogd) kan polls lezen
CREATE POLICY "Polls zijn zichtbaar voor iedereen"
ON polls FOR SELECT
USING (true);

-- Alleen ingelogde gebruikers kunnen polls aanmaken
-- user_id moet overeenkomen met de ingelogde gebruiker
CREATE POLICY "Ingelogde gebruikers kunnen polls aanmaken"
ON polls FOR INSERT
WITH CHECK (auth.uid() = user_id);

-- Alleen de eigenaar kan zijn poll updaten
CREATE POLICY "Eigenaar kan eigen poll updaten"
ON polls FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);

-- Alleen de eigenaar kan zijn poll verwijderen
CREATE POLICY "Eigenaar kan eigen poll verwijderen"
ON polls FOR DELETE
USING (auth.uid() = user_id);
```

### Stap 4: Verifieer je policies

```sql
-- Bekijk alle policies op de polls tabel
SELECT policyname, cmd, qual, with_check
FROM pg_policies
WHERE tablename = 'polls';
```

---

## Appendix C: Troubleshooting

### Veelvoorkomende fouten en oplossingen

#### 1. "new row violates row-level security policy"

**Oorzaak:** De `user_id` die je meestuurt komt niet overeen met de ingelogde gebruiker, of je bent niet ingelogd.

**Oplossing:**
```javascript
// Controleer of de gebruiker is ingelogd
const { data: { user } } = await supabase.auth.getUser()
console.log('Ingelogde user:', user)

// Zorg dat user_id overeenkomt
const { data, error } = await supabase
  .from('polls')
  .insert({
    question: 'Test vraag?',
    user_id: user.id  // Moet het ID van de ingelogde user zijn
  })

if (error) console.error('Insert error:', error)
```

#### 2. "Invalid redirect URL" bij Google OAuth

**Oorzaak:** De redirect URL in Google Cloud Console komt niet overeen met die van Supabase.

**Oplossing:**
- De redirect URL moet exact zijn: `https://<project-id>.supabase.co/auth/v1/callback`
- Controleer op typefouten en extra spaties
- Wacht een paar minuten na het toevoegen (Google kan traag zijn)

#### 3. "Access blocked: This app's request is invalid" bij Google login

**Oorzaak:** OAuth consent screen is niet correct geconfigureerd.

**Oplossing:**
- Controleer of je je eigen email als test user hebt toegevoegd
- Controleer of de OAuth consent screen status "Testing" is
- Zorg dat de juiste scopes zijn ingesteld (email en profile)

#### 4. Polls worden niet zichtbaar na toevoegen van RLS

**Oorzaak:** RLS is ingeschakeld maar er is geen SELECT policy.

**Oplossing:**
```sql
-- Controleer of RLS is ingeschakeld
SELECT tablename, rowsecurity
FROM pg_tables
WHERE tablename = 'polls';

-- Controleer of er een SELECT policy is
SELECT * FROM pg_policies
WHERE tablename = 'polls' AND cmd = 'SELECT';
```

#### 5. Gebruiker kan andermans poll toch bewerken

**Oorzaak:** De UPDATE/DELETE policy is niet correct, of RLS staat niet aan.

**Oplossing:**
```sql
-- Zorg dat RLS is ingeschakeld
ALTER TABLE polls ENABLE ROW LEVEL SECURITY;

-- Test de policy met een specifieke user
-- In de SQL Editor kun je een andere user simuleren:
SET request.jwt.claims = '{"sub": "andere-user-id"}';
SELECT * FROM polls; -- zou alleen polls van die user moeten tonen voor UPDATE
```

#### 6. Google login knop doet niets

**Oorzaak:** JavaScript error of Supabase client niet correct geinitialiseerd.

**Oplossing:**
- Open de browser console (F12) en check op errors
- Controleer of `supabase` correct is geinitialiseerd
- Controleer of de functie correct is gekoppeld aan de knop

```javascript
// Debug: test of Supabase client werkt
console.log('Supabase client:', supabase)
console.log('Auth beschikbaar:', supabase.auth)
```

---

**Veel succes! Denk goed na over je eindexamenopdracht - het wordt het leukste deel van de cursus.**
