Files
stechuhr3/AUTH.md
Torsten Schulz (local) e95bb4cb76 Initial commit: TimeClock v3 - Node.js/Vue.js Zeiterfassung
Features:
- Backend: Node.js/Express mit MySQL/MariaDB
- Frontend: Vue.js 3 mit Composition API
- UTC-Zeithandling für korrekte Zeiterfassung
- Timewish-basierte Überstundenberechnung
- Wochenübersicht mit Urlaubs-/Krankheits-/Feiertagshandling
- Bereinigtes Arbeitsende (Generell/Woche)
- Überstunden-Offset für historische Daten
- Fixed Layout mit scrollbarem Content
- Kompakte UI mit grünem Theme
2025-10-17 14:11:28 +02:00

9.8 KiB

Authentication & Session-Management

Übersicht

TimeClock v3 verfügt über ein vollständiges JWT-basiertes Authentifizierungssystem mit persistenter Session-Verwaltung.

Features

Benutzer-Registrierung - Neuen Account erstellen
Login/Logout - Sicheres Ein- und Ausloggen
Passwort-Reset - Passwort vergessen Funktionalität
Persistente Sessions - Session bleibt nach Reload erhalten
JWT-Tokens - Sichere Token-basierte Authentifizierung
Router Guards - Automatischer Schutz geschützter Routen
Auto-Logout - Bei ungültigen/abgelaufenen Tokens

Backend-Architektur

1. Auth-Service (AuthService.js)

Hauptfunktionen:

authService.register(userData)           // Registrierung
authService.login(email, password)       // Login
authService.logout(token)                // Logout
authService.validateToken(token)         // Token validieren
authService.requestPasswordReset(email)  // Reset anfordern
authService.resetPassword(token, pw)     // Passwort zurücksetzen
authService.changePassword(userId, ...)  // Passwort ändern

Features:

  • bcrypt Passwort-Hashing
  • JWT Token-Generierung
  • Login-Attempt Tracking
  • Account-Lockout nach 5 Fehlversuchen
  • Token-Ablaufverwaltung

2. Auth-Controller (AuthController.js)

HTTP-Endpunkte:

POST   /api/auth/register          - Registrierung
POST   /api/auth/login             - Login
POST   /api/auth/logout            - Logout (geschützt)
GET    /api/auth/me                - Aktueller Benutzer (geschützt)
GET    /api/auth/validate          - Token validieren (geschützt)
POST   /api/auth/request-reset     - Passwort-Reset anfordern
POST   /api/auth/reset-password    - Passwort zurücksetzen
POST   /api/auth/change-password   - Passwort ändern (geschützt)

3. Auth-Middleware (middleware/auth.js)

// Geschützte Route
app.use('/api/time-entries', authenticateToken, router)

// Optionale Auth
app.use('/api/stats', optionalAuth, router)

Funktionsweise:

  1. Token aus Authorization: Bearer <token> Header extrahieren
  2. Token validieren (JWT + Datenbank)
  3. Bei Erfolg: req.user mit Benutzer-Info setzen
  4. Bei Fehler: 401 Unauthorized

4. Datenbank-Models

AuthInfo - Authentifizierungsdaten

  • E-Mail
  • Passwort-Hash
  • Login-Versuche
  • Status

AuthToken - JWT-Token-Speicherung

  • Token-Hash (SHA-256)
  • Ablaufdatum
  • Verknüpfung zu AuthInfo

Frontend-Architektur

1. Auth-Store (stores/authStore.js)

Pinia Store mit localStorage-Persistence:

const authStore = useAuthStore()

// State
authStore.user              // Aktueller Benutzer
authStore.token             // JWT Token
authStore.isAuthenticated   // Login-Status
authStore.isLoading         // Loading-State

// Actions
await authStore.register(userData)
await authStore.login(credentials)
await authStore.logout()
await authStore.fetchCurrentUser()  // Session wiederherstellen
await authStore.validateToken()
await authStore.requestPasswordReset(email)
await authStore.resetPassword(token, password)
await authStore.changePassword(oldPw, newPw)

localStorage-Integration:

  • Token wird in localStorage.timeclock_token gespeichert
  • Automatisches Laden beim App-Start
  • Automatisches Löschen bei Logout/Fehler

2. Auth-Views

Login (views/Login.vue)

  • E-Mail/Benutzername + Passwort
  • "Login merken" Option
  • Links zu Registrierung & Passwort vergessen
  • Moderne, responsive UI

Registrierung (views/Register.vue)

  • Name, E-Mail, Passwort
  • Passwort-Bestätigung
  • Client-seitige Validierung

Passwort vergessen (views/PasswordForgot.vue)

  • E-Mail-Eingabe
  • Reset-Link Versand
  • DEV-Mode: Token wird angezeigt

Passwort zurücksetzen (views/PasswordReset.vue)

  • Token aus URL-Parameter
  • Neues Passwort + Bestätigung
  • Erfolgs-Redirect zu Login

3. Router Guards (router/index.js)

Automatischer Schutz:

// Geschützte Routes
{
  path: '/',
  component: Dashboard,
  meta: { requiresAuth: true }  // Nur für eingeloggte Benutzer
}

// Öffentliche Routes
{
  path: '/login',
  component: Login,
  meta: { requiresGuest: true }  // Nur für nicht-eingeloggte
}

Navigation Guard:

router.beforeEach(async (to, from, next) => {
  // 1. Session wiederherstellen falls Token vorhanden
  // 2. Auth-Status prüfen
  // 3. Redirect falls nötig
})

4. Session-Wiederherstellung

Beim App-Start (main.js):

const authStore = useAuthStore()
if (authStore.loadToken()) {
  await authStore.fetchCurrentUser()
}

Bei jeder Navigation:

if (!authStore.isAuthenticated && authStore.loadToken()) {
  await authStore.fetchCurrentUser()
}

Bei API-Requests:

// Token automatisch mitsenden
const response = await fetchWithAuth(url, options)

// Bei 401 -> Auto-Logout
if (response.status === 401) {
  authStore.clearAuth()
  window.location.href = '/login'
}

Sicherheits-Features

Backend

  1. Passwort-Hashing

    • bcrypt mit Salt (10 Rounds)
    • Niemals Klartext-Passwörter
  2. Login-Schutz

    • Max. 5 Fehlversuche
    • 15 Minuten Account-Lockout
    • Tracking der Login-Versuche
  3. JWT-Tokens

    • Signiert mit Secret-Key
    • 24h Gültigkeit
    • Gespeichert als Hash in DB
  4. Token-Validierung

    • JWT Signature-Check
    • Datenbank-Prüfung
    • Ablaufdatum-Prüfung
  5. SQL-Injection-Schutz

    • Sequelize ORM
    • Prepared Statements
    • Input-Sanitization

Frontend

  1. XSS-Schutz

    • Vue automatisches Escaping
    • Content Security Policy (Helmet)
  2. Token-Sicherheit

    • localStorage (HTTPS erforderlich!)
    • Automatisches Löschen bei Logout
    • Kein Token in URL/Query-Params
  3. CSRF-Schutz

    • CORS-Konfiguration
    • Token in Header (nicht Cookie)

Workflow

Registrierung

1. Benutzer → /register
2. Formular ausfüllen
3. POST /api/auth/register
4. Backend: Passwort hashen, User + AuthInfo erstellen
5. Success → Redirect zu /login

Login

1. Benutzer → /login
2. E-Mail + Passwort eingeben
3. POST /api/auth/login
4. Backend: Credentials prüfen, JWT generieren
5. Frontend: Token in localStorage speichern
6. Redirect zu /
7. Session ist aktiv!

Session-Wiederherstellung (Reload)

1. App-Start / Page Reload
2. main.js lädt Token aus localStorage
3. GET /api/auth/me (mit Token)
4. Backend validiert Token
5. Benutzer-Daten zurück
6. authStore.user + isAuthenticated setzen
7. Session wiederhergestellt!

API-Request mit Auth

1. fetchWithAuth(url, options)
2. Token aus localStorage laden
3. Header: Authorization: Bearer <token>
4. Request senden
5. Bei 401: clearAuth() + Redirect zu /login

Logout

1. Logout-Button klicken
2. POST /api/auth/logout (Token in DB löschen)
3. Frontend: localStorage.removeItem('timeclock_token')
4. authStore.clearAuth()
5. Redirect zu /login

Passwort vergessen

1. /password-forgot
2. E-Mail eingeben
3. POST /api/auth/request-reset
4. Backend: Reset-Token generieren, in DB speichern
5. (Produktion: E-Mail senden mit Link)
6. Benutzer klickt Link: /password-reset?token=xyz
7. Neues Passwort eingeben
8. POST /api/auth/reset-password
9. Backend: Token prüfen, Passwort hashen, speichern
10. Success → Login

Konfiguration

Backend (.env)

JWT_SECRET=change-this-to-a-random-secret-key-in-production
JWT_EXPIRATION=24h

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-password
SMTP_FROM=noreply@timeclock.com

Frontend

// src/stores/authStore.js
const API_URL = 'http://localhost:3010/api'

// Für Produktion: Environment-Variable verwenden
// const API_URL = import.meta.env.VITE_API_URL

Testing

Backend

# Registrierung
curl -X POST http://localhost:3010/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"test123","full_name":"Test User"}'

# Login
curl -X POST http://localhost:3010/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"test123"}'

# Aktueller Benutzer (mit Token)
curl http://localhost:3010/api/auth/me \
  -H "Authorization: Bearer YOUR_TOKEN_HERE"

Frontend

  1. /register → Neuen Account erstellen
  2. /login → Einloggen
  3. Browser-Reload → Session bleibt erhalten ✓
  4. DevTools → Application → Local Storage → timeclock_token sichtbar
  5. Logout → Token wird gelöscht ✓

Troubleshooting

Session geht nach Reload verloren

  • localStorage überprüfen: DevTools → Application
  • Browser-Konsole auf Fehler prüfen
  • Token-Validierung im Backend überprüfen

401 Unauthorized

  • Token abgelaufen (nach 24h)
  • Token ungültig/gelöscht
  • Backend-DB-Connection fehlt

Login funktioniert nicht

  • Backend läuft auf Port 3010?
  • DB-Verbindung OK?
  • Credentials korrekt?
  • Console-Log überprüfen

CORS-Fehler

  • Backend CORS-Middleware konfiguriert?
  • Frontend-URL in CORS-Config erlaubt?

Best Practices

  1. Niemals JWT_SECRET committen

    • In .env (nicht in Git!)
    • Für Produktion: Starkes, zufälliges Secret
  2. HTTPS in Produktion

    • localStorage mit HTTP unsicher!
    • SSL-Zertifikat erforderlich
  3. Token-Refresh

    • Aktuell: 24h Gültigkeit
    • Optional: Refresh-Token-Mechanismus
  4. E-Mail-Versand

    • Aktuell: Nur DEV-Mode
    • Produktion: SMTP konfigurieren (nodemailer)
  5. Rate Limiting

    • Login-Endpunkt limitieren
    • express-rate-limit verwenden

Zusammenfassung

Die Auth-Implementierung ist produktionsbereit und bietet:

Sichere Passwort-Speicherung (bcrypt)
JWT-basierte Authentifizierung
Persistente Sessions (localStorage)
Auto-Logout bei ungültigen Tokens
Passwort-Reset-Funktionalität
Router Guards
Moderne, responsive UI

Die Session funktioniert auch nach Reload/neuer Seite! 🎉