JWT oder Session? Nach diesem Guide ist die Entscheidung klar

Der Cursor blinkt zwischen session: { strategy: "jwt" } und session: { strategy: "database" }. Das Release steht an – und Sie fragen sich noch: JWT oder Session?
Bei der Technologieauswahl wirken beide Optionen gut, aber welche passt wirklich zu Ihrem Projekt? JWT ist zustandslos und spart DB-Abfragen, lässt sich aber nicht sofort widerrufen. Session erlaubt sofortige Kontrolle, kostet aber pro Request eine Datenbankabfrage. In diesem Artikel gehen wir die Unterschiede und die Entscheidung durch.
Zuerst: Was sind JWT und Session?
Viele können Definitionen aufsagen – klar erklären ist schwerer. Ein Bild hilft:
Session ist wie eine Mitgliedskarte im Fitnessstudio. Beim Abschluss trägt das Studio Ihre Daten im System. Beim Besuch reicht das Scannen (Session-ID) – die Rezeption sieht Status, Laufzeit und Restkontingent. Alles Wichtige liegt in der Datenbank des Studios.
JWT ist wie ein Ausweis. Name, Geburtsdatum, Adresse stehen auf dem Dokument. Zur Identifikation zeigen Sie den Ausweis – ohne Nachschlagen in einem externen System.
Daraus folgt das Verhalten:
-
Session: Nach dem Login erzeugt der Server eine Session-ID, speichert Nutzerdaten in der DB und sendet die ID per Cookie an den Browser. Jede weitere Anfrage bringt die Session-ID mit – der Server liest die zugehörigen Daten aus der DB.
-
JWT: Nach dem Login packt der Server Nutzerinfos in ein signiertes Token (JWT) und sendet es an den Browser. Bei jeder Anfrage prüft der Server nur die Gültigkeit des Tokens – ohne DB-Zugriff.
JWT im Detail
Warum JWT so beliebt ist
JWT ist in der Community stark verbreitet – besonders bei Serverless und Microservices. Der Hauptgrund: weniger Datenbankdruck.
Ein Bekannter betreibt einen E-Commerce-Shop auf Vercel mit JWT. Sein Fazit: „Weniger Aufwand“ – keine Sorge um Connection-Limits oder Session-Tabellen-Performance, Edge-Deployment problemlos. Einmal einloggen, JWT mitgeben, Server prüft die Signatur – fertig.
JWT passt besonders zu:
1. Serverless / Edge
Auf Vercel, Cloudflare Workers & Co. ist JWT oft Standard. Funktionen sind zustandslos, Requests landen auf verschiedenen Instanzen. Mit Session bräuchten Sie Redis o. Ä. für gemeinsame Session-Daten. Mit JWT reicht das Token – jede Instanz verarbeitet gleich.
2. Hohe Last
Bei Flash-Sales ist die DB der Engpass. Mit Session: jede Anfrage eine Abfrage. Mit JWT: nur beim Login die DB, danach lokale Validierung – deutlich schneller.
3. Microservices
Bei mehreren Services (User, Order, Payment) teilen sich JWTs die Auth-Infos. Kein zentraler Session-Store, kein Session-Lookup pro Service.
Fallstricke bei JWT
Klingt gut – aber es gibt echte Stolpersteine.
Größtes Problem: kein sofortiger Widerruf
Einmal mussten wir ein kompromittiertes Konto sofort abmelden. Mit Session: DB-Eintrag löschen – erledigt. Mit JWT: peinlich – bis zum Ablauf bleibt das Token gültig.
Blacklist? Geht – aber dann verlieren Sie den Stateless-Vorteil. Jede Anfrage prüft die Liste – ähnlich wie eine Session-Tabelle.
Deshalb: kurze Laufzeit (z. B. 15 Minuten) plus Refresh Token. Gestohlenes Token ist spätestens dann tot.
Cookie-Größenlimit
JWT codiert Nutzerdaten ins Token. Rollen, Rechte, Einstellungen – das Token wächst. Browser-Cookies sind auf etwa 4 KB begrenzt.
Faustregel: nur das Nötigste ins JWT – z. B. User-ID und Ablaufzeit. Rest bei Bedarf nachladen.
NextAuth.js: JWT in der Praxis
Mit Next.js ist NextAuth.js (Auth.js) die verbreitete Lösung. JWT-Konfiguration ist überschaubar:
// auth.ts
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [GitHub],
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 Tage
},
callbacks: {
async jwt({ token, user }) {
// Beim ersten Login User-Infos ins Token
if (user) {
token.id = user.id
token.role = user.role
}
return token
},
async session({ session, token }) {
// Token-Infos an den Client durchreichen
if (token) {
session.user.id = token.id
session.user.role = token.role
}
return session
},
},
})
Wichtige Punkte:
-
NEXTAUTH_SECRETsetzen (Auth.js v5:AUTH_SECRET). Mitnpx auth secreterzeugen. Signiert und verschlüsselt das JWT – nicht leaken. -
Rolling Session: Bei Aktivität automatisch verlängern mit
updateAge:
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60,
updateAge: 24 * 60 * 60, // alle 24 Stunden erneuern
}
Bei Aktivität innerhalb von 24 Stunden verlängert sich die Session – kein überraschendes Abmelden.
- Edge Runtime (2025): Für Middleware die Konfiguration splitten:
// auth.config.ts – läuft auf Edge
export default {
providers: [GitHub],
session: { strategy: "jwt" },
}
// auth.ts – DB-Operationen nur auf Node.js
import { PrismaAdapter } from "@auth/prisma-adapter"
import authConfig from "./auth.config"
export const { handlers, auth } = NextAuth({
...authConfig,
adapter: PrismaAdapter(prisma),
})
Edge Runtime unterstützt nicht alle Node-APIs. Middleware nutzt auth.config.ts, Server-Routen die vollständige auth.ts.
Database Session im Detail
Wann Session Pflicht ist
JWT ist praktisch – aber manche Szenarien verlangen Session.
Ein Backoffice für eine Finanzfirma: bei verdächtigem Login sofort abmelden – harte Anforderung. JWT passt da schlecht.
Database Session eignet sich für:
1. Sofortige Kontrolle
Gerätelimit (nur ein Gerät), Admin-Kick, alle Sessions nach Passwortänderung invalidieren – mit Session trivial, mit JWT viel Zusatzlogik.
2. Hohe Sicherheit
Banken, Medizin, Behörden: jede Anfrage soll den aktuellen Berechtigungsstand aus der DB haben. Session liefert das; JWT kann veraltete Claims tragen.
3. Klassischer Monolith
App und DB auf einem Stack – Session-Lookup ist günstig, Sessions lassen sich zentral steuern.
Performance bei Session
Jede Anfrage trifft die Datenbank – bei hohem Traffic ein Engpass.
Optimierungen:
-
Redis für Sessions – schneller als klassische DB, mit TTL.
-
Minimale Session-Daten – nur User-ID, Rest bei Bedarf.
-
Ablaufzeiten und Aufräumen – sonst wächst die Session-Tabelle endlos.
Next.js: Session-Konfiguration
NextAuth.js nutzt standardmäßig JWT. Für Database Session brauchen Sie einen Adapter:
// auth.ts
import NextAuth from "next-auth"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
import GitHub from "next-auth/providers/github"
const prisma = new PrismaClient()
export const { handlers, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [GitHub],
session: {
strategy: "database",
maxAge: 30 * 24 * 60 * 60, // 30 Tage
updateAge: 24 * 60 * 60, // täglich aktualisieren
},
})
Prisma legt die Session-Tabelle an – npx prisma db push:
// schema.prisma
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id String @id @default(cuid())
email String @unique
sessions Session[]
}
Performance-Tipps:
-
Index auf
sessionTokenundexpires. -
Abgelaufene Sessions regelmäßig löschen:
// cleanup-sessions.ts
async function cleanupExpiredSessions() {
await prisma.session.deleteMany({
where: {
expires: {
lt: new Date(),
},
},
})
}
// täglich um 3 Uhr
Entscheidungsrahmen aus der Praxis
Theorie reicht nicht – hier ein Framework für Ihr Projekt:
Nach Projekttyp
| Projekttyp | Empfehlung | Begründung |
|---|---|---|
| Serverless | JWT | Zustandslos, kein gemeinsamer Session-Store |
| Monolith | Session | DB nah, Lookup günstig |
| Microservices | JWT oder Hybrid | Auth über Services hinweg |
| Content/Blog | JWT | Einfache Auth, JWT reicht |
| SaaS-Backoffice | Session | Feine Rechte- und Session-Kontrolle |
Nach Sicherheitsniveau
- Niedrig (Blog, Forum): JWT, z. B. 30 Tage Ablauf
- Mittel (E-Commerce, Social): JWT + kurze Laufzeit + Refresh Token
- Hoch (Finanzen, Medizin, Admin): Session + kurze Laufzeit + Rolling Session
Fallstudien
Fall 1: E-Commerce – JWT
Der Shop auf Vercel wählte JWT:
- Serverless passt zu JWT
- Weniger DB-Last bei vielen Nutzern
- Session-Kontrolle weniger kritisch; langsames Token-Ablauf nach Logout akzeptabel
Kompromiss: JWT-Laufzeit 7 statt 30 Tage – gestohlene Tokens verlieren schneller an Wert.
Fall 2: OA-System – Session
Internes OA mit Session:
- Rollenänderungen sofort wirksam
- Limit gleichzeitiger Geräte
- Intranet – DB-Latenz vernachlässigbar
Session mit Redis: Antwortzeiten unter 50 ms.
Fall 3: Hybrid – wie Clerk
Viele Auth-Plattformen (Clerk, Auth0) mischen:
- Kurzlebiger Token (JWT, ~15 Min.) für API-Aufrufe
- Refresh Token in der DB
- Session-Records für Widerruf aus der Ferne
Performance von JWT, Kontrolle von Session – aufwendiger in der Eigenimplementierung.
Unsere Empfehlung
-
Standard: JWT – für die meisten Projekte ausreichend, einfach, performant.
-
Session, wenn:
- Gerätelimit nötig
- sofortiger Kick erforderlich
- Finanzen/Medizin o. Ä.
- alle Logins nach Passwortänderung sofort ungültig
-
Kein Over-Engineering – kleines Projekt: einfache Lösung zuerst. Hybrid am Anfang bläht oft die Komplexität ohne echten Nutzen.
Ablauf und UX: Best Practices
Die gewählte Strategie muss Ablauf sauber handhaben – sonst leidet die UX.
JWT-Ablauf
Klassischer Frust: Formular ausfüllen, Submit – „Session abgelaufen“, Inhalt weg.
Lösung: Refresh Token + stilles Refresh
-
Zwei Tokens:
- Access Token: ~15 Minuten für API
- Refresh Token: ~30 Tage für neues Access Token
-
Frontend erneuert Access Token kurz vor Ablauf (z. B. bei 2 Minuten Rest)
-
Nutzer merkt nichts
NextAuth.js unterstützt das Muster – Beispiel:
callbacks: {
async jwt({ token, user, account }) {
if (account && user) {
// Erster Login
return {
...token,
accessToken: account.access_token,
accessTokenExpires: Date.now() + account.expires_in * 1000,
refreshToken: account.refresh_token,
}
}
// Access Token noch gültig
if (Date.now() < token.accessTokenExpires) {
return token
}
// Abgelaufen – Refresh
return refreshAccessToken(token)
},
}
async function refreshAccessToken(token) {
try {
const response = await fetch("https://api.example.com/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
client_id: process.env.OAUTH_CLIENT_ID,
grant_type: "refresh_token",
refresh_token: token.refreshToken,
}),
})
const refreshedTokens = await response.json()
return {
...token,
accessToken: refreshedTokens.access_token,
accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,
}
} catch (error) {
return {
...token,
error: "RefreshAccessTokenError",
}
}
}
Session-Ablauf
Rolling Session vs. absolutes Timeout
- Rolling: Aktivität verlängert die Session – Standard für die meisten Apps
- Absolut: Festes Ende unabhängig von Aktivität – z. B. Banking
NextAuth.js:
session: {
strategy: "database",
maxAge: 2 * 60 * 60, // 2 Stunden absolut
updateAge: 30 * 60, // bei Aktivität innerhalb 30 Min. verlängern
}
Aktivität innerhalb von 30 Minuten verlängert; spätestens nach 2 Stunden ist Schluss.
Idle-Timeout
„15 Minuten ohne Aktion abmelden“ – z. B. im Frontend:
let idleTimer
function resetIdleTimer() {
clearTimeout(idleTimer)
idleTimer = setTimeout(() => {
// 15 Minuten idle → abmelden
signOut()
}, 15 * 60 * 1000)
}
// Nutzeraktivität
document.addEventListener("mousemove", resetIdleTimer)
document.addEventListener("keypress", resetIdleTimer)
Trends 2025
Hybrid im Mainstream
Teams kombinieren:
- JWT für API (schnell)
- aktive Sessions in der DB (kontrollierbar)
Clerk, Auth0 & Co. folgen diesem Muster – oder den Dienst direkt nutzen.
Edge Runtime
Next.js-Middleware auf Edge begünstigt JWT. Schutz ganzer Bereiche (z. B. /dashboard) in der Middleware ist mit JWT oft einfacher.
Passkey und WebAuthn
Passkeys (WebAuthn) – Login per Fingerabdruck/Face ID ohne Passwort – werden häufiger. NextAuth.js v5 unterstützt Passkey; Auth-Flows werden reicher, UX oft besser.
Abschluss
Sie sollten JWT und Session nun klarer einordnen können. Es gibt keine Universalantwort – Stärken verstehen und zum Projekt passen.
Unsere Erfahrung: Für die meisten Projekte reicht JWT; bei Bedarf an sofortiger Kontrolle Session. Nicht zu früh verkomplizieren – einfache Lösungen sind oft die zuverlässigsten.
Noch unsicher? Starten Sie mit NextAuth.js-Default (JWT), messen Sie in Produktion. Wechsel zu Session ist meist wenige Zeilen Konfiguration.
Wenn Sie um drei Uhr morgens noch zwischen jwt und database hängen: eine Nacht Schlaf hilft oft mehr als eine weitere Stunde Docs. Und wenn Ihr Szenario hier fehlt – gerne in den Kommenten diskutieren; gemeinsam findet man meist die passende Variante.
FAQ
Was ist der Kernunterschied zwischen JWT und Session?
Wann JWT, wann Session?
JWT lässt sich nicht sofort widerrufen – was tun?
Wie optimiert man Session-Performance?
Wie konfiguriert man JWT und Session in NextAuth.js?
Wie handhabt man Ablauf und UX?
Welche Trends 2025 für JWT und Session?
8 Min. Lesezeit · Veröffentlicht am: 19. Dez. 2025 · Aktualisiert am: 14. Juli 2026
Next.js Komplettleitfaden
Wenn du über die Suche hier gelandet bist, kommst du am schnellsten weiter, indem du zum vorherigen oder nächsten Beitrag dieser Serie springst.
Vorheriger
NextAuth.js Einstieg: Credentials-Login und Session-Management – Komplett-Guide
NextAuth.js wirkt komplex? Dieser Artikel konzentriert sich auf Credentials-Login, die Wahl JWT vs. Session, mit vollständigen Codebeispielen und Fallstricken – ideal für Next.js-Entwickler, die schnell ein Authentifizierungssystem aufsetzen wollen.
Teil 48 von 51
Nächster
SWR – vollständiger Leitfaden: Cache-Strategien und optimistische Updates in der Praxis
Lernen Sie die Kernkonzepte und Cache-Strategien von SWR kennen und vereinfachen Sie bis zu 90 % Ihres Datenabruf-Codes mit einem Hook. Inklusive Praxisbeispielen für optimistische Updates, Vergleich mit React Query und Best Practices für die Next.js-Integration.
Teil 50 von 51
Ähnliche Beiträge
Next.js App Router Einstieg: Kernkonzepte und Grundlagen im Überblick

Next.js App Router Einstieg: Kernkonzepte und Grundlagen im Überblick
Next.js 15 in der Praxis: Wie ich an einem Wochenende ein produktionsreifes Blog-System aufgebaut habe


Kommentare
Melde dich mit GitHub an, um einen Kommentar zu hinterlassen