Wat is Authentication?
Nu kan iedereen alle workouts zien en aanpassen. Niet veilig. Met authentication kan elke gebruiker alleen hun eigen workouts beheren.
Hoe werkt het?
1. Registreren: Maak account met email en wachtwoord
2. Inloggen: Backend geeft token (toegangspas)
3. Token meesturen: Bij elk request stuur je token mee
4. Backend checkt: Is token geldig? Zo ja, je mag door
Twee belangrijke packages
1. JWT (JSON Web Token)
Dit is lange string die bewijst dat je bent ingelogd:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NzRhM2Y4ZDk4...
Je hoeft niet te begrijpen HOE dit werkt. Je moet alleen weten:
- Backend maakt token na inloggen
- Frontend stuurt token mee bij elk request
- Token bevat je user ID
- Token is 7 dagen geldig
2. bcrypt (Password Hashing)
bcrypt versleutelt wachtwoorden. Iemand hackt je database? Dan zien ze niet "Piet123" maar dit:
$2b$10$KmX8Yv3Lq9Np2Rs4Tw5Ux.HpZcJ6Tv8GcL4mN9oP...
Zo zijn wachtwoorden veilig, zelfs als database gehackt wordt.
Stap 1: Packages Installeren
Installeer in je backend:
npm install jsonwebtoken bcrypt
jsonwebtoken- Voor maken en verifiëren JWT tokensbcrypt- Voor hashen wachtwoorden
Stap 2: User Model Maken
Maak nieuw bestand: src/models/User.js
import mongoose from 'mongoose';
import bcrypt from 'bcrypt';
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
lowercase: true
},
password: {
type: String,
required: true,
minlength: 6
}
}, {
timestamps: true
});
// Dit gebeurt automatisch VOOR het opslaan
userSchema.pre('save', async function() {
if (!this.isModified('password')) {
return;
}
// Hash het wachtwoord
this.password = await bcrypt.hash(this.password, 10);
});
// Functie om wachtwoorden te vergelijken
userSchema.methods.comparePassword = async function(candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};
const User = mongoose.model('User', userSchema);
export default User;
unique: true- Elk email maar 1x gebruikenlowercase: true- Zet email naar kleine lettersminlength: 6- Wachtwoord minimaal 6 karakters
Wat doet pre('save')?
Dit draait automatisch VOOR user wordt opgeslagen.
Als je doet: User.create({ email, password })
Dan gebeurt:
- Mongoose runt eerst pre('save')
- Wachtwoord wordt gehashed
- Dan pas opslaan in database
Jij hoeft dit niet handmatig te doen - Mongoose doet automatisch!
Wat doet comparePassword?
Custom functie die je later gebruikt:
const isMatch = await user.comparePassword('Piet123');
Vergelijkt normaal wachtwoord met gehashte wachtwoord in database.
Stap 3: JWT Secret Toevoegen
Open .env en voeg toe:
JWT_SECRET=mijn_super_geheime_string_12345
Wat is JWT_SECRET?
Geheime sleutel om tokens te maken. Gebruik lange willekeurige string. Mag NOOIT gedeeld worden.
Zelf een veilige secret genereren
Voer dit uit in je terminal om een willekeurige secret te maken:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
Kopieer de output en plak die als waarde in je .env:
JWT_SECRET=a3f8c2e1b4d6f9a2c5e8b1d4f7a0c3e6...
Stap 4: Auth Controller Maken
Maak nieuw bestand: src/controllers/authController.js
import User from '../models/User.js';
import jwt from 'jsonwebtoken';
// Helper functie om token te maken
const createToken = (userId) => {
return jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: '7d'
});
};
// REGISTER - nieuwe gebruiker aanmaken
export const register = async (req, res) => {
const { email, password } = req.body;
try {
// Check of email al bestaat
const exists = await User.findOne({ email });
if (exists) {
return res.status(400).json({ error: 'Email is al in gebruik' });
}
// Check of velden ingevuld zijn
if (!email || !password) {
return res.status(400).json({ error: 'Vul alle velden in' });
}
// Check wachtwoord lengte
if (password.length < 6) {
return res.status(400).json({
error: 'Wachtwoord moet minimaal 6 karakters zijn'
});
}
// Maak nieuwe gebruiker
const user = await User.create({ email, password });
// Maak token
const token = createToken(user._id);
// Stuur token terug
res.status(201).json({ email: user.email, token });
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
};
// LOGIN - bestaande gebruiker inloggen
export const login = async (req, res) => {
const { email, password } = req.body;
try {
// Check of velden ingevuld zijn
if (!email || !password) {
return res.status(400).json({ error: 'Vul alle velden in' });
}
// Zoek gebruiker
const user = await User.findOne({ email });
if (!user) {
return res.status(400).json({
error: 'Email of wachtwoord incorrect'
});
}
// Check wachtwoord
const isMatch = await user.comparePassword(password);
if (!isMatch) {
return res.status(400).json({
error: 'Email of wachtwoord incorrect'
});
}
// Maak token
const token = createToken(user._id);
// Stuur token terug
res.status(200).json({ email: user.email, token });
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
};
createToken()- Maakt JWT token met user IDexpiresIn: '7d'- Token 7 dagen geldig- Register: Checkt of email uniek is, maakt user, geeft token
- Login: Zoekt user, checkt wachtwoord, geeft token
Waarom niet "email bestaat niet" of "wachtwoord fout"?
We zeggen altijd "Email of wachtwoord incorrect". Dit is voor security - hackers kunnen anders raden welke emails bestaan.
Stap 5: Auth Routes Maken
Maak nieuw bestand: src/routes/authRoutes.js
import express from 'express';
import { register, login } from '../controllers/authController.js';
const router = express.Router();
// POST /api/auth/register
router.post('/register', register);
// POST /api/auth/login
router.post('/login', login);
export default router;
Voeg 2 regels voor de route toe aan server.js:
import express from 'express';
import cors from 'cors';
import mongoose from 'mongoose';
import workoutRoutes from './src/routes/workoutRoutes.js';
import authRoutes from './src/routes/authRoutes.js'; // Voeg deze regel toe
const app = express();
app.use(cors({ origin: 'http://localhost:5173' }));
app.use(express.json());
// Routes
app.use('/api/workouts', workoutRoutes);
app.use('/api/auth', authRoutes); // Voeg deze regel toe
// Database verbinden en server starten
mongoose.connect(process.env.MONGO_URI)
.then(() => {
app.listen(process.env.PORT, () => {
console.log('Database verbonden & server draait');
});
})
.catch((err) => console.error(err));
Stap 6: Testen met Postman
Test 1: Registreren
- Method: POST
- URL:
http://localhost:4000/api/auth/register - Body (raw JSON):
{
"email": "test@test.nl",
"password": "test123"
}
Verwacht resultaat:
Status: 201 Created
{
"email": "test@test.nl",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Test 2: Inloggen
- Method: POST
- URL:
http://localhost:4000/api/auth/login - Body (raw JSON):
{
"email": "test@test.nl",
"password": "test123"
}
Verwacht resultaat:
Status: 200 OK
Zelfde response als register (email + token)
Test 3: Foute Credentials
Probeer inloggen met verkeerd wachtwoord:
{
"email": "test@test.nl",
"password": "fout_wachtwoord"
}
Verwacht resultaat:
Status: 400 Bad Request
{
"error": "Email of wachtwoord incorrect"
}
Veelvoorkomende Fouten
❌ "Email is al in gebruik"
Probleem: Account met dit email bestaat al
Oplossing: Gebruik ander email of log in met bestaand account
❌ Wachtwoord niet gehashed
Probleem: Wachtwoord staat als platte tekst in database
Check:
userSchema.pre('save')correct in User.js?- Check MongoDB Atlas - wachtwoord moet lange onleesbare string zijn
- Verwijder verkeerde users en maak opnieuw aan
❌ "Email of wachtwoord incorrect" bij login
Check:
- Email adres bestaat? (registreer eerst!)
- Wachtwoord correct ingetypt?
- comparePassword functie werkt in User model?
❌ Geen token in response
Check:
- JWT_SECRET in .env?
- createToken() functie returnt token?
- res.json({ email, token }) en niet alleen email?
Samenvatting
Je hebt nu basis authentication werkend!
Wat je hebt gemaakt:
- User model met password hashing
- Register endpoint (POST /api/auth/register)
- Login endpoint (POST /api/auth/login)
- JWT tokens die je kan gebruiken
Test alles goed!
Zorg dat je meerdere accounts kan maken en kan inloggen. Je krijgt elke keer token terug. Deze tokens ga je in volgende deel gebruiken om routes te beveiligen.
Volgende Stap
Je hebt accounts en tokens. Tijd om routes te beveiligen.
Beveilig je workout routes met middleware