Files
ausgaben-next/AUTH_README.md
T
admin d3718da1f8 V 2.2.1 Anmeldung per Passkey (WebAuthn)
Passkey-Login analog zu werte-next: auf der Login-Seite "Mit Passkey
anmelden", Verwaltung der eigenen Passkeys im neuen Tab Einstellungen.
Das Passwort bleibt als Alternative bestehen.

- lib/webauthn.ts, lib/passkeys.ts sowie API-Routen unter /api/passkey
- proxy.ts: /api/passkey/authenticate ohne Session erreichbar
- TabLayout: dritter Tab Einstellungen (Index-Tabs statt Route wie werte)
- RP-Konfiguration ueber AUSGABEN_RP_*, da sich die .env auf dem Server
  mit anderen Apps teilt, die RP_ID/RP_ORIGIN bereits belegen
- Eigene Tabelle ausgaben_passkeys aus demselben Grund: werte-next nutzt
  in der gemeinsamen Datenbank RXF bereits die Tabelle passkeys
- eslint.config.mjs auf die Flat-Config von eslint-config-next umgestellt

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 16:35:35 +02:00

6.3 KiB

Wiederverwendbare Authentifizierung

Diese Authentifizierungslösung kann einfach in andere Next.js Projekte übernommen werden.

Komponenten

1. Core Libraries (wiederverwendbar)

  • /lib/auth.ts - Authentifizierungslogik (Benutzerverwaltung über .env)
  • /lib/session.ts - JWT-basiertes Session-Management
  • /middleware.ts - Route-Schutz Middleware
  • /lib/webauthn.ts - Passkey-Logik (Registrierung & Anmeldung, WebAuthn)
  • /lib/passkeys.ts - Datenbankzugriff auf die Tabelle ausgaben_passkeys

2. UI Komponenten (wiederverwendbar)

  • /app/login/page.tsx - Login-Seite (Passwort + „Mit Passkey anmelden")
  • /app/login/actions.ts - Server Actions für Login/Logout
  • /components/LogoutButton.tsx - Logout-Button Komponente
  • /components/Passkeys.tsx - Verwaltung der eigenen Passkeys (Tab Einstellungen)

3. API-Routen (Passkeys)

  • /app/api/passkey/route.ts - eigene Passkeys auflisten (GET) / löschen (DELETE)
  • /app/api/passkey/register/route.ts - Passkey registrieren (Session erforderlich)
  • /app/api/passkey/authenticate/route.ts - Anmeldung per Passkey (öffentlich)

Installation in neuen Projekten

1. Dependencies installieren

npm install jose bcryptjs
npm install --save-dev @types/bcryptjs

# Für Passkeys (WebAuthn):
npm install @simplewebauthn/server @simplewebauthn/browser

2. Dateien kopieren

Kopiere folgende Dateien in dein neues Projekt:

  • lib/auth.ts
  • lib/session.ts
  • middleware.ts
  • app/login/ (gesamter Ordner)
  • scripts/generate-password.js (Passwort-Hash Generator)
  • components/LogoutButton.tsx (optional)

3. Passwort-Hashes generieren

Verwende das mitgelieferte Script, um sichere Passwort-Hashes zu erstellen:

# Interactive Mode
node scripts/generate-password.js

# Mit Passwort als Argument
node scripts/generate-password.js meinPasswort123

Das Script gibt einen bcrypt-Hash aus, den du in der .env verwenden kannst.

4. Umgebungsvariablen einrichten

Füge zu deiner .env hinzu:

# Authentifizierung
# Format: username:passwordHash,username2:passwordHash2
# Verwende 'node scripts/generate-password.js' um Hashes zu generieren
AUTH_USERS=admin:$2b$10$DKLO7uQPmdAw9Z64NChro...,user1:$2b$10$K613Z70Hodr6xyEh10Mw2u...

# Secret Key für JWT (unbedingt ändern in Production!)
AUTH_SECRET=your-super-secret-key-change-this

# Passkeys (WebAuthn) — RP_ID = nur der Host, RP_ORIGIN = volle URL
RP_ID=ausgaben.fuerst-stuttgart.de
RP_ORIGIN=https://ausgaben.fuerst-stuttgart.de
RP_NAME=Ausgaben-Log

5. Logout-Button einbinden (optional)

import LogoutButton from '@/components/LogoutButton';

// In deiner Komponente:
<LogoutButton />

Konfiguration

Benutzer hinzufügen/entfernen

  1. Generiere einen Passwort-Hash:
node scripts/generate-password.js neuesPasswort
  1. Editiere die AUTH_USERS Variable in der .env:
AUTH_USERS=user1:$2b$10$hash1...,user2:$2b$10$hash2...,user3:$2b$10$hash3...

Authentifizierung deaktivieren

Entferne die AUTH_USERS Variable oder setze sie auf einen leeren String:

AUTH_USERS=

Session-Dauer anpassen

Editiere in lib/session.ts:

const SESSION_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 Tage

Geschützte Routen anpassen

Editiere in middleware.ts die publicPaths:

const publicPaths = ['/login', '/api/passkey/authenticate', '/public-page'];

Die Passkey-Anmeldung muss ohne Session erreichbar sein.

Passkeys verwalten

  • Registrieren: angemeldet im Tab Einstellungen → „Passkey hinzufügen".
  • Anmelden: auf der Login-Seite „Mit Passkey anmelden".
  • Speicherung: Tabelle ausgaben_passkeys (siehe create_table.sql), wird beim ersten Zugriff automatisch angelegt, sofern der DB-Benutzer CREATE-Rechte hat. Wichtig bei Übernahme in ein anderes Projekt: Teilen sich mehrere Apps eine Datenbank, braucht jede App einen eigenen Tabellennamen (TABLE in lib/passkeys.ts) — sonst sehen und löschen sie gegenseitig ihre Passkeys.
  • RP_ID muss exakt dem Hostnamen entsprechen (ohne Protokoll/Port). Ändert sich RP_ID, werden bereits registrierte Passkeys ungültig.
  • WebAuthn funktioniert nur über HTTPS oder auf localhost.

Sicherheitshinweise

  1. AUTH_SECRET ändern: Verwende in Production einen starken, zufälligen Schlüssel
  2. HTTPS verwenden: In Production immer HTTPS aktivieren
  3. Passwort-Hashing: Passwörter werden mit bcrypt gehashed (10 Salt Rounds)
  4. Keine Klartext-Passwörter: Verwende immer das Script zur Hash-Generierung

Passwort-Hash Generator

Das Script scripts/generate-password.js verwendet bcrypt mit 10 Salt Rounds, um sichere Passwort-Hashes zu erstellen.

Verwendung

Interactive Mode (empfohlen für sensible Passwörter):

npm run generate-password
# oder
node scripts/generate-password.js
# Passwort wird interaktiv abgefragt

Mit Argument:

npm run generate-password -- meinPasswort
# oder
node scripts/generate-password.js meinPasswort

Ausgabe

🔐 Generiere Passwort-Hash...

✅ Hash generiert:
────────────────────────────────────────────────────────────────────────────────
$2b$10$DKLO7uQPmdAw9Z64NChro.8mOsnqZQaRZjctWDojIkK926ROBVyJW
────────────────────────────────────────────────────────────────────────────────

📝 Verwende diesen Hash in der .env Datei:
AUTH_USERS=username:$2b$10$DKLO7uQPmdAw9Z64NChro.8mOsnqZQaRZjctWDojIkK926ROBVyJW

Erweiterte Verwendung

Session-Informationen abrufen

import { getSession } from '@/lib/session';

const session = await getSession();
if (session) {
  console.log('Eingeloggt als:', session.username);
}

Programmatisch prüfen, ob authentifiziert

import { isAuthenticated } from '@/lib/session';

const authenticated = await isAuthenticated();

In Server Components

import { getSession } from '@/lib/session';
import { redirect } from 'next/navigation';

export default async function ProtectedPage() {
  const session = await getSession();
  
  if (!session) {
    redirect('/login');
  }
  
  return <div>Hallo {session.username}!</div>;
}