session management analysis - smart-village-solutions/sva-studio GitHub Wiki
Erstellt: 2026-02-04 Status: Vorschlag für Architekturentscheidung Kontext: [Issue zur Auth-Implementierung] & Milestone 1
Die damalige Auth-Implementierung (packages/auth, historisch) nutzte In-Memory-Session-Storage:
// packages/auth-runtime/src/session.ts
const sessions = new Map<string, Session>();
const loginStates = new Map<string, LoginState>();Probleme:
- ❌ Sessions gehen bei Server-Restart/HMR verloren
- ❌ Nicht skalierbar (nur ein Prozess/Server)
- ❌ Keine Persistenz bei Deployment/Rollouts
- ❌ Kein Cluster-Betrieb möglich
Nach Login-Redirect von Keycloak wird die Session initial erstellt, aber:
- Bei Dev-Server-Reload (HMR) ist die Map leer
- User sieht "Nicht eingeloggt", obwohl Cookie gesetzt wurde
- Callback-Flow funktioniert grundsätzlich, aber Session-Persistenz fehlt
- Multi-Mandanten-Fähigkeit: Verschiedene Organisationen mit isolierten Sessions
- Skalierbarkeit: Horizontal skalierbar (mehrere Backend-Instanzen)
- Performance: Berechtigungsprüfung < 50 ms (laut Konzeption)
- OIDC/Keycloak-Integration: Access Token, Refresh Token, ID Token verwalten
- Session-Refresh: Automatisches Token-Refresh ohne Neuanmeldung
Sicherheit & Compliance:
- DSGVO-konform (Datenminimierung, Verschlüsselung)
- BSI-Grundschutz
- HttpOnly, Secure, SameSite Cookies
- Session-Timeout & Auto-Logout
Betrieb & Wartbarkeit:
- Open Source First (keine proprietären Cloud-Dienste zwingend)
- Self-Hosted-Fähigkeit für Kommunen
- Monitoring & Observability
- Disaster Recovery & Backup
Performance:
- Session-Lookup < 10 ms
- Berechtigungsprüfung < 50 ms (mit Caching)
- Keine blockierenden Disk-I/O im Request-Path
Konzept:
- Session-Daten vollständig im Cookie (JWE/signed)
- Kein Server-Side-Storage nötig
- Stateless
Vorteile:
- ✅ Keine externe Abhängigkeit (Redis, DB)
- ✅ Horizontal skalierbar (stateless)
- ✅ Einfaches Deployment
- ✅ Schnell (keine DB-Abfrage)
Nachteile:
- ❌ Cookie-Größenlimit (~4 KB)
- ❌ Sensitive Daten im Browser (verschlüsselt, aber risiko)
- ❌ Kein serverseitiges Session-Revoke (nur über Token-Blacklist)
- ❌ Größere Tokens bei vielen Rollen/Orgs
Bewertung: Gut für einfache Use-Cases, aber problematisch bei:
- Vielen Organisationszugehörigkeiten
- Komplexen Berechtigungsstrukturen (siehe 7-Personas-System)
- Impersonation/Support-Sessions
Konzept:
- Session-ID im Cookie
- Session-Daten in Redis (Key-Value)
- TTL-basierte Auto-Expiration
Vorteile:
- ✅ Sehr schnell (< 1 ms Latenz)
- ✅ Horizontal skalierbar (Redis Cluster)
- ✅ TTL/Expiration eingebaut
- ✅ Session-Revoke möglich (DELETE key)
- ✅ Pub/Sub für Cache-Invalidierung
Nachteile:
⚠️ Externe Abhängigkeit (Redis-Server)⚠️ Keine Persistenz bei Redis-Restart (außer RDB/AOF)⚠️ Zusätzlicher Infrastruktur-Komponente
Bewertung: Empfohlene Lösung für Phase 1–2, weil:
- Passt zur Konzeption (Redis bereits für Permission-Cache geplant)
- Ausgezeichnetes Performance-Profil
- Bewährte Technologie (express-session, connect-redis)
Konzept:
- Session-ID im Cookie
- Session-Daten in Postgres-Tabelle
- Cleanup via Cron-Job oder TTL-Extension (pg_cron)
Vorteile:
- ✅ Vollständige Persistenz
- ✅ Transaktionale Konsistenz mit User-Daten
- ✅ Einfaches Backup/Recovery
- ✅ Audit-Trail möglich (Session-History)
- ✅ Keine zusätzliche Infrastruktur (wenn Postgres schon da)
Nachteile:
- ❌ Langsamer als Redis (5–20 ms statt < 1 ms)
- ❌ Höhere DB-Last bei vielen Sessions
- ❌ Connection-Pool-Overhead
Bewertung: Sinnvoll für langfristige Architektur oder wenn:
- Keine Redis-Infrastruktur gewünscht
- Sessions mit User-Änderungen transaktional verknüpft werden sollen
- Maximale Daten-Persistenz erforderlich
Konzept:
- Hot Storage: Aktive Sessions in Redis (< 1 h)
- Cold Storage: Ältere Sessions in DB (für Audit)
- Automatisches Tiering
Vorteile:
- ✅ Beste Performance für aktive Sessions
- ✅ Audit-Fähigkeit durch DB-Persistenz
- ✅ Session-History für Compliance
Nachteile:
⚠️ Höhere Komplexität (2 Stores)⚠️ Sync-Mechanismus nötig
Bewertung: Für spätere Phasen relevant, wenn:
- Umfangreiches Session-Audit erforderlich
- Langzeit-Analyse von Login-Mustern
- Forensik/Compliance-Anforderungen steigen
Begründung:
- Projektkonzeption passt: Redis bereits für Permission-Cache vorgesehen
- Performance-Ziele erfüllbar: < 50 ms Berechtigungsprüfung nur mit Caching realistisch
- Skalierbarkeit: Horizontal skalierbar, Cloud-Ready
- Einfache Migration: Von In-Memory zu Redis ist straightforward
- Open Source: Redis ist FOSS, self-hosted möglich
Umsetzungsschritte:
// packages/auth-runtime/src/redis-session.ts
import { createClient } from 'redis';
const redis = createClient({
url: process.env.REDIS_URL || 'redis://localhost:6379'
});
export const createSession = async (session: Session) => {
const ttl = 60 * 60 * 24 * 7; // 7 Tage
await redis.setEx(
`session:${session.id}`,
ttl,
JSON.stringify(session)
);
};
export const getSession = async (sessionId: string): Promise<Session | null> => {
const data = await redis.get(`session:${sessionId}`);
return data ? JSON.parse(data) : null;
};
export const deleteSession = async (sessionId: string) => {
await redis.del(`session:${sessionId}`);
};- Session-User-Permissions aus Permission-Engine cachen
- Invalidierung via Pub/Sub
- Shared Cache für Sessions + Permissions
- Redis Sentinel oder Cluster für HA
- Session-Replikation
- Monitoring (Redis Insights, Prometheus)
Wann relevant?
- Audit-Trail-Anforderungen steigen
- DSGVO-Auskunftsanfragen (welche Sessions hatte User X?)
- Forensik nach Security-Incident
- Langzeit-Analyse von Login-Mustern
Umsetzung:
// Schreibe aktive Session in Redis + DB
await Promise.all([
redis.setEx(`session:${id}`, ttl, JSON.stringify(session)),
db.sessions.create({ ...session, expiresAt: new Date(Date.now() + ttl * 1000) })
]);
// Cleanup alter DB-Sessions via Cron
await db.sessions.deleteMany({
expiresAt: { lt: new Date() },
createdAt: { lt: subMonths(new Date(), 3) } // 3-Monats-Retention
});Falls Kommune Redis ablehnt:
- Postgres-Session-Store nutzen
- Query-Optimierung (Index auf session_id + expires_at)
- Connection-Pooling optimieren
- Eventuell: pgBouncer für Session-Pooling
Performance-Tuning:
CREATE INDEX idx_sessions_lookup ON iam.sessions(id, expires_at)
WHERE expires_at > NOW();
-- Partitionierung nach Monat für große Installationen
CREATE TABLE iam.sessions_2026_02 PARTITION OF iam.sessions
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');Key-Pattern:
session:{sessionId} -> JSON Session-Objekt
session:user:{userId}:active -> Set von Session-IDs (für Multi-Device)
session:state:{state} -> Login-State (PKCE, nur 10 min TTL)
Session-Objekt:
interface Session {
id: string;
user: SessionUser;
accessToken: string;
refreshToken?: string;
idToken?: string;
expiresAt?: number;
createdAt: number;
lastActivity: number;
ipAddress?: string;
userAgent?: string;
// Für Impersonation/Support
impersonatedBy?: string;
originalUserId?: string;
}Encryption at Rest:
import { createCipheriv, createDecipheriv } from 'crypto';
const encrypt = (data: string): string => {
const cipher = createCipheriv('aes-256-gcm', key, iv);
// ... Verschlüsselung
};
await redis.setEx(
`session:${id}`,
ttl,
encrypt(JSON.stringify(session))
);Session-Fixation-Schutz:
// Bei Login: Neue Session-ID generieren
const newSessionId = randomUUID();
await deleteSession(oldSessionId); // Alte Session löschen
await createSession({ ...session, id: newSessionId });IP-Binding (optional):
const session = await getSession(sessionId);
if (session.ipAddress !== request.ip) {
throw new Error('Session IP mismatch');
}Metriken (Prometheus):
-
session_create_total(Counter) -
session_get_duration_seconds(Histogram) -
session_active_total(Gauge) -
session_expired_total(Counter)
Health-Check:
export const healthCheck = async () => {
try {
await redis.ping();
return { status: 'healthy', latency: latency };
} catch (error) {
return { status: 'unhealthy', error };
}
};# Docker Compose für lokale Entwicklung
services:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yesCode-Änderungen:
- Historischer Schritt:
redisim damaligen Auth-Package ergänzen; heute liegt die Umsetzung inpackages/auth-runtime -
session.ts→session.redis.tsmit async Funktionen -
auth.server.ts: Alle Session-Callsawait -
.env.local:REDIS_URL=redis://localhost:6379
Optionen:
- Redis Cloud (free tier für testing)
- AWS ElastiCache (wenn AWS-Hosting)
- Self-Hosted (Redis auf VM, Ansible-Playbook)
Config:
REDIS_URL=redis://:[email protected]:6379
REDIS_TLS=true
REDIS_CLUSTER_MODE=trueRedis Sentinel:
services:
redis-master:
image: redis:7-alpine
redis-replica-1:
image: redis:7-alpine
command: redis-server --replicaof redis-master 6379
sentinel:
image: redis:7-alpine
command: redis-sentinel /etc/redis/sentinel.confClient-Code:
import { createClient } from 'redis';
const client = createClient({
socket: {
host: process.env.REDIS_SENTINEL_HOST,
port: 26379
},
sentinel: {
name: 'mymaster',
sentinelPassword: process.env.REDIS_SENTINEL_PASSWORD
}
});Idee: Keycloak als einzige Session-Authority.
Contra:
- Keycloak-Sessions sind für SSO optimiert, nicht für App-State
- Keine feingranularen CMS-spezifischen Session-Daten
- Performance-Overhead (HTTP-Call zu Keycloak bei jedem Request)
- Vendor Lock-in (schwer zu migrieren)
Fazit: Keycloak für Authentifizierung, CMS für Session-State.
Idee: Supabase hat eingebautes Auth-System.
Contra:
- Wir nutzen bereits Keycloak (Projektanforderung)
- Supabase Auth ist weniger flexibel für Custom-Flows
- Keine Passkeys/FIDO2-Unterstützung (Stand 2026)
Fazit: Supabase nur als Datenbank, Keycloak als IdP.
Idee: Nur Access Token, kein Session-Store.
Contra:
- Kein Session-Revoke (Logout wirkt erst nach Token-Expiry)
- Refresh-Token-Rotation kompliziert
- Impersonation/Support-Sessions schwierig
- Token-Größe bei vielen Claims (Permissions, Orgs)
Fazit: Hybrid-Ansatz: Short-Lived Access Token (15 min) + Server-Side-Session für Refresh Token.
-
Redis-Hosting-Strategie:
- Managed Service (Redis Cloud, AWS) vs. Self-Hosted?
- Budget-Freigabe nötig?
-
Backup & Recovery:
- RDB-Snapshots täglich?
- AOF für Point-in-Time-Recovery?
-
Monitoring-Stack:
- Prometheus + Grafana bereits vorhanden?
- Alert-Regeln für Session-Store-Ausfälle?
-
DSGVO-Retention:
- Session-Daten nach 30 Tagen löschen?
- Audit-Log in DB für 90 Tage behalten?
- Redis-Setup in
docker-compose.ymlfür lokale Dev - Historischer Punkt: Redis-Session-Storage ist heute in
packages/auth-runtime/src/redis-session.tsumgesetzt. - Integration-Tests mit Testcontainers
- Staging-Deployment mit Redis Cloud (Free Tier)
- Performance-Benchmarks (Session-Lookup < 10 ms)
- Security-Review (Encryption, Session-Fixation)
- Dokumentation für Deployment-Team
Für SVA Studio empfehle ich:
-
Jetzt (Milestone 1): Redis Session Store implementieren
- Schnell, bewährt, passt zur Architektur
- Minimale Infrastruktur-Änderung (Redis lokal/Docker)
- Basis für späteren Permission-Cache
-
Später (Milestone 3+): Hybrid Redis + DB
- Für Audit-Trail & Compliance
- Session-History für DSGVO-Auskunft
- Forensik nach Security-Incidents
-
Fallback: DB-Only für Self-Hosted ohne Redis
- Performance-Tuning erforderlich
- Aber funktional vollständig
Vorteile für Projekt:
- ✅ Open Source (Redis ist FOSS)
- ✅ Self-Hosted-fähig (keine Cloud-Pflicht)
- ✅ Skalierbar (Cluster-Mode)
- ✅ DSGVO-konform (Data Residency)
- ✅ BSI-konform (Verschlüsselung, Monitoring)
- ✅ Community-Standard (express-session, connect-redis)
Nächster Schritt: Implementierungs-Ticket erstellen + Tech-Review im Team.
Aus Security-Sicht ist die Redis-Strategie grundsätzlich passend und skalierbar. Vor Umsetzung müssen jedoch Key-Management (KMS/Rotation), Token-Schutz im Session-Store sowie ein verbindliches Retention-/Löschkonzept festgelegt werden, um DSGVO/BSI-Anforderungen zu erfüllen.
Statement (UX & Accessibility Reviewer): Die Analyse adressiert UX/A11y nur indirekt. Für die Umsetzung sollten klare Session-Timeout- und Re-Login-Flows mit barrierefreien Hinweisen (Screenreader-Text, Fokus-Management, eindeutige Fehlermeldungen) verbindlich ergänzt werden, damit Nutzer:innen nicht unerwartet aus Sitzungen fallen.
Statement (Operations & Reliability Reviewer): Die Analyse benennt Redis als zentrale Betriebsabhängigkeit, aber es fehlen konkrete Runbooks, RTO/RPO‑Ziele, Backup/Restore‑Verfahren und ein belastbarer HA‑Plan (Sentinel/Cluster) inkl. Monitoring/Alerting. Für einen 24/7‑Betrieb müssen diese Punkte verbindlich festgelegt und getestet werden (insb. Failover‑Tests, Restore‑Drills, Ressourcen‑Sizing).
Statement (Interoperability & Data Reviewer): Die Analyse ist technisch schlüssig, adressiert aber Interoperabilität nur indirekt. Für Wechsel- und Migrationsfähigkeit fehlen klare Vorgaben zu Export/Import von Sessions/Audit-Daten, Versionierung der Auth-API sowie ein dokumentierter Deprecation‑Pfad. Ohne diese Standards ist die Exit‑Fähigkeit eingeschränkt und ein Anbieterwechsel risikobehaftet.
Statement (Architecture & FIT Compliance Reviewer): Die Redis-Empfehlung ist aus Skalierungs- und API‑First‑Sicht plausibel und kompatibel mit dem Headless‑Ansatz. Für FIT‑Konformität fehlen jedoch explizite ADRs zur Abgrenzung Keycloak vs. CMS‑IAM, zum Vendor‑Lock‑in‑Risiko (Redis/Keycloak) sowie zu offenen Standards (OIDC/SAML/SCIM‑Erweiterungen). Diese Entscheidungen sollten dokumentiert werden, um Abweichungen nachvollziehbar zu machen.