Doel van deze store
De auth store houdt bij wie er is ingelogd. Hij wordt door je hele app gebruikt:
- De header toont "Hallo, Anna" als iemand is ingelogd
- Een "Profiel" link verschijnt alleen voor ingelogde gebruikers
- Beveiligde routes checken of de gebruiker mag passeren
- De login & register pagina's zetten de gebruiker erin
Volgorde: deze pagina bouwt voort op Pinia en localStorage. Lees die eerst als je nog niet bekend bent met die concepten.
De auth store
Maak src/stores/auth.js:
// src/stores/auth.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useAuthStore = defineStore('auth', () => {
// State
const user = ref(null)
// Computed
const isLoggedIn = computed(() => user.value !== null)
// Actions
const login = (userData) => {
user.value = userData
}
const logout = () => {
user.value = null
}
return { user, isLoggedIn, login, logout }
})
Drie ingrediënten:
user— null = niet ingelogd, object = ingelogdisLoggedIn— handige computed booleanlogin&logout— twee acties dieuseraanpassen
Persisteren in localStorage
Zonder persistence wordt de gebruiker uitgelogd bij elke refresh. Voeg twee dingen toe:
- Bij setup: lees de gebruiker uit localStorage (als die er is)
- Bij login/logout: schrijf de wijziging naar localStorage
// src/stores/auth.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useAuthStore = defineStore('auth', () => {
// 1. Lees opgeslagen user (of null)
const stored = localStorage.getItem('user')
const user = ref(stored ? JSON.parse(stored) : null)
const isLoggedIn = computed(() => user.value !== null)
const login = (userData) => {
user.value = userData
// 2a. Schrijf bij login
localStorage.setItem('user', JSON.stringify(userData))
}
const logout = () => {
user.value = null
// 2b. Wis bij logout
localStorage.removeItem('user')
}
return { user, isLoggedIn, login, logout }
})
Wat heb je nu? De gebruiker blijft ingelogd na een refresh. Logt uit → de localStorage wordt geleegd. Eén bron van waarheid.
Voor demo-projecten is dit prima. In productie sla je het token (niet het complete user-object) op, en bij voorkeur in een HTTP-only cookie om XSS-aanvallen te voorkomen. Maar dat is een onderwerp voor later.
Gebruiken in components
Header met conditionele content
<!-- src/components/Header.vue -->
<script setup>
import { useAuthStore } from '@/stores/auth'
const auth = useAuthStore()
</script>
<template>
<header>
<RouterLink to="/">Home</RouterLink>
<!-- Niet ingelogd -->
<template v-if="!auth.isLoggedIn">
<RouterLink to="/login">Inloggen</RouterLink>
<RouterLink to="/register">Registreren</RouterLink>
</template>
<!-- Wel ingelogd -->
<template v-else>
<span>Hallo, {{ auth.user.name }}</span>
<button @click="auth.logout">Uitloggen</button>
</template>
</header>
</template>
Logout knop ergens anders
<script setup>
import { useAuthStore } from '@/stores/auth'
import { useRouter } from 'vue-router'
const auth = useAuthStore()
const router = useRouter()
const handleLogout = () => {
auth.logout()
router.push('/login')
}
</script>
<template>
<button @click="handleLogout">Uitloggen</button>
</template>
De volgende pagina's gebruiken deze store:
- Login & Register — roepen
auth.login()aan - Protected Routes — checken
auth.isLoggedIn
Belangrijke Regels
- Eén auth store voor de hele app — niet meerdere
- State + actions samen in de store, niet verspreiden
- Persisteren met localStorage in
login/logout - Bij setup lezen in de ref-initialisatie
- Components mogen
auth.userlezen, maar muteren alleen vialogin/logout
Veelgemaakte Fouten
Fout — localStorage vergeten bij logout:
const logout = () => {
user.value = null
// ❌ localStorage blijft staan — refresh logt user weer in
}
Goed:
const logout = () => {
user.value = null
localStorage.removeItem('user') // ✅
}
Fout — JSON.parse op een null-waarde zonder check:
const user = ref(JSON.parse(localStorage.getItem('user')))
// ❌ als de key niet bestaat: JSON.parse(null) → null (toevallig OK)
// Maar bij beschadigde data → crash
Goed:
const stored = localStorage.getItem('user')
const user = ref(stored ? JSON.parse(stored) : null) // ✅