Uitleg — Overzicht
Je hebt twee aparte flows nodig:
| Flow | Wat er gebeurt |
|---|---|
| Registreren | Eigen API route die de gebruiker opslaat in MongoDB met een gehashed wachtwoord |
| Inloggen | NextAuth signIn() die de authorize functie aanroept en een sessie aanmaakt |
💡 Mappenstructuur voor auth
app/
├── api/
│ ├── auth/
│ │ └── [...nextauth]/
│ │ └── route.js ← al aangemaakt
│ └── register/
│ └── route.js ← nieuw
├── register/
│ └── page.js ← nieuw
└── login/
└── page.js ← nieuw
Stap 1 — Maak de registratie API route aan
Maak een nieuw bestand app/api/register/route.js aan:
app/api/register/route.js
// app/api/register/route.js
import { NextResponse } from 'next/server';
import bcrypt from 'bcryptjs';
import connectDB from '../../../lib/mongodb';
import User from '../../../models/User';
export async function POST(request) {
const { name, email, password } = await request.json();
// Validatie
if (!name || !email || !password) {
return NextResponse.json(
{ error: 'Vul alle velden in' },
{ status: 400 }
);
}
if (password.length < 6) {
return NextResponse.json(
{ error: 'Wachtwoord moet minimaal 6 tekens zijn' },
{ status: 400 }
);
}
await connectDB();
// Check of email al bestaat
const exists = await User.findOne({ email });
if (exists) {
return NextResponse.json(
{ error: 'Dit e-mailadres is al in gebruik' },
{ status: 400 }
);
}
// Wachtwoord hashen voor opslag
const hashedPassword = await bcrypt.hash(password, 10);
await User.create({ name, email, password: hashedPassword });
return NextResponse.json(
{ message: 'Account aangemaakt' },
{ status: 201 }
);
}
- Zet het wachtwoord om in een hash:
"geheim123" → "$2b$10$abc..." - De
10is het aantal "salt rounds" — hoe hoger, hoe veiliger maar langzamer - Elke hash is uniek, ook als twee gebruikers hetzelfde wachtwoord hebben
Stap 2 — Maak het registratieformulier aan
Maak een nieuw bestand app/components/RegisterForm.js aan:
// app/components/RegisterForm.js
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
export default function RegisterForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(null);
const router = useRouter();
async function handleSubmit(e) {
e.preventDefault();
setError(null);
const res = await fetch('/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email, password }),
});
const data = await res.json();
if (!res.ok) {
setError(data.error);
return;
}
// Account aangemaakt — stuur door naar inlogpagina
router.push('/login');
}
return (
<form onSubmit={handleSubmit} style={{ maxWidth: '400px', margin: '0 auto' }}>
<h1>Account aanmaken</h1>
<div>
<label>Naam</label>
<input
type="text"
placeholder="Jouw naam"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div>
<label>E-mailadres</label>
<input
type="email"
placeholder="naam@voorbeeld.nl"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div>
<label>Wachtwoord</label>
<input
type="password"
placeholder="Minimaal 6 tekens"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button type="submit">Account aanmaken</button>
<p>Al een account? <Link href="/login">Inloggen</Link></p>
</form>
);
}
Stap 3 — Maak de registratiepagina aan
Maak een nieuw bestand app/register/page.js aan:
// app/register/page.js
import RegisterForm from '../components/RegisterForm';
export default function RegisterPage() {
return <RegisterForm />;
}
✅ Test het
Ga naar http://localhost:3000/register en maak een account aan. Controleer in MongoDB Atlas of de gebruiker is opgeslagen — het wachtwoord moet een hash zijn, niet de platte tekst.
Stap 4 — Maak het loginformulier aan
Maak een nieuw bestand app/components/LoginForm.js aan. Dit gebruikt signIn van NextAuth — geen eigen API route nodig:
// app/components/LoginForm.js
'use client';
import { useState } from 'react';
import { signIn } from 'next-auth/react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
export default function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(null);
const router = useRouter();
async function handleSubmit(e) {
e.preventDefault();
setError(null);
const result = await signIn('credentials', {
email,
password,
redirect: false, // Wij handelen de redirect zelf af
});
if (result?.error) {
setError('Ongeldig e-mailadres of wachtwoord');
return;
}
// Ingelogd! Stuur door naar workouts
router.push('/workouts');
router.refresh();
}
return (
<form onSubmit={handleSubmit} style={{ maxWidth: '400px', margin: '0 auto' }}>
<h1>Inloggen</h1>
<div>
<label>E-mailadres</label>
<input
type="email"
placeholder="naam@voorbeeld.nl"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div>
<label>Wachtwoord</label>
<input
type="password"
placeholder="Jouw wachtwoord"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button type="submit">Inloggen</button>
<p>Nog geen account? <Link href="/register">Registreren</Link></p>
</form>
);
}
- Met
redirect: truelaat NextAuth de redirect afhandelen — je hebt minder controle - Met
redirect: falsekrijg je eenresultobject terug en handel je de redirect zelf af - Dit is handiger omdat je dan een foutmelding kunt tonen zonder pagina-herlaad
Stap 5 — Maak de loginpagina aan
Maak een nieuw bestand app/login/page.js aan:
// app/login/page.js
import LoginForm from '../components/LoginForm';
export default function LoginPage() {
return <LoginForm />;
}
✅ Test het
Ga naar http://localhost:3000/login en log in met het account dat je zojuist aanmaakte. Na succesvol inloggen word je doorgestuurd naar /workouts.
Stap 6 — Maak de uitlogknop aan en voeg toe aan layout
Maak een nieuw bestand app/components/LogoutButton.js aan:
// app/components/LogoutButton.js
'use client';
import { signOut } from 'next-auth/react';
export default function LogoutButton() {
return (
<button onClick={() => signOut({ callbackUrl: '/login' })}>
Uitloggen
</button>
);
}
Vervang daarna de inhoud van app/layout.js om de knop toe te voegen:
// app/layout.js
import './globals.css';
import Link from 'next/link';
import AuthProvider from './components/AuthProvider';
import LogoutButton from './components/LogoutButton';
export default function RootLayout({ children }) {
return (
<html lang="nl">
<body>
<AuthProvider>
<nav>
<Link href="/">Home</Link>
<Link href="/workouts">Workouts</Link>
<LogoutButton />
</nav>
<main>{children}</main>
</AuthProvider>
</body>
</html>
);
}
💡 callbackUrl
callbackUrl: '/login' stuurt de gebruiker na uitloggen door naar de loginpagina. Zonder dit gaat NextAuth naar de homepage.
Checklist
✅ Check of je hebt:
app/api/register/route.jsaangemaaktapp/components/RegisterForm.jsaangemaaktapp/register/page.jsaangemaaktapp/components/LoginForm.jsaangemaaktapp/login/page.jsaangemaaktapp/components/LogoutButton.jsaangemaakt- Registreren werkt — gebruiker zichtbaar in MongoDB
- Inloggen werkt — doorgestuurd naar
/workouts - Uitloggen werkt — doorgestuurd naar
/login
Volgende Stap
Inloggen werkt! Nu beveiligen we de pagina's zodat alleen ingelogde gebruikers ze kunnen zien.
Beveilig pagina's voor niet-ingelogde gebruikers