Wenn du eine API baust, stößt du früher oder später auf eine Frage: Nachdem sich ein Nutzer eingeloggt hat, wie erkenne ich ihn bei jeder folgenden Anfrage wieder? Die Antwort auf was ist JWT liegt genau hier. Ein JWT (JSON Web Token) ist wie ein in sich geschlossener Ausweis, den der Server erstellt, signiert und dem Client übergibt. Der Client schickt diesen Ausweis bei jeder Anfrage zurück, und der Server kann die Signatur prüfen und sagen: "Ja, das ist wirklich ein Token, das ich ausgestellt habe" — ohne jemals die Datenbank zu befragen.
Was ist JWT und warum verwendet man es?
Beim klassischen Session-Management hält der Server für jeden eingeloggten Nutzer einen Session-Eintrag und gibt dem Client eine Session-ID. Das funktioniert, aber der Server muss einen Zustand merken. Hast du mehrere Server, müssen sie alle denselben Session-Speicher teilen.
JWT kehrt das um. Das Token trägt selbst die Informationen über den Nutzer (wer er ist, seine Rolle, eine Ablaufzeit) und ist mit dem geheimen Schlüssel des Servers signiert. Der Server muss sich nichts merken; er muss nur die Signatur des eingehenden Tokens prüfen. Deshalb nennt man JWT stateless (zustandslose) Authentifizierung, und genau das macht es in Microservices, Mobile-Apps und APIs so verbreitet.
Die drei Teile eines Tokens
Ein JWT besteht aus drei durch Punkte getrennten Teilen: header.payload.signature. Jeder Teil ist Base64Url-kodiert (kodiert, nicht verschlüsselt — ein wichtiger Unterschied).
- Header: nennt den Token-Typ und den verwendeten Signaturalgorithmus. Beispiel:
{"alg":"HS256","typ":"JWT"}. - Payload (Nutzlast): trägt die sogenannten Claims — etwa die Nutzer-ID (
sub), die Ablaufzeit (exp), den Erstellungszeitpunkt (iat) und Felder, die du selbst hinzufügst (wie eine Rolle). - Signature (Signatur): Header und Payload, signiert mit dem geheimen Schlüssel. Dieser Teil garantiert, dass das Token nicht manipuliert wurde.
Ein echtes Token sieht so aus:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3MTk1MDAwMDB9
.s5_3kF9vQk2...signatur
Ein entscheidender Punkt: Die Payload ist nicht verschlüsselt. Jeder kann Base64Url dekodieren und lesen. Lege deshalb niemals Geheimnisse wie Passwörter oder Kreditkartennummern in ein Token. Ein Token trägt eine "Identität", keine Geheimnisse.
Wie funktioniert das Signieren?
Die Signatur ist das Herz des gesamten Sicherheitsmodells von JWT. Beim Algorithmus HS256 (HMAC + SHA-256) wird die Signatur so berechnet:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
geheimerSchluessel
)
Wenn der Server ein Token prüft, wiederholt er genau dieselbe Operation: Er signiert den eingehenden Header und die Payload erneut mit seinem eigenen geheimen Schlüssel und vergleicht das Ergebnis mit der Signatur im Token. Versucht jemand, die Rolle in der Payload von user auf admin zu ändern, stimmt die Signatur nicht mehr, denn der Angreifer hat den geheimen Schlüssel nicht. Deshalb ist das Token "fälschungssicher".
Es gibt zwei Signaturansätze:
- HS256 (symmetrisch): Ein einziger geheimer Schlüssel signiert und prüft. Einfach und schnell, aber wer prüfen kann, kann auch Tokens ausstellen.
- RS256 (asymmetrisch): Signiert mit einem privaten Schlüssel, prüft mit einem öffentlichen Schlüssel. Ideal, wenn mehrere Dienste Tokens prüfen müssen, sie aber nicht ausstellen dürfen.
In der Praxis: ein Token ausstellen und prüfen
In Node.js wirkt der Ablauf mit der Bibliothek jsonwebtoken sehr übersichtlich:
const jwt = require('jsonwebtoken');
// Nach erfolgreichem Login ein Token ausstellen
const token = jwt.sign(
{ sub: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
// Bei folgenden Anfragen prüfen
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
// Nutzer über payload.sub identifizieren
} catch (err) {
// ungültige Signatur oder abgelaufen
}
Der Client schickt dieses Token meist im Header Authorization: Bearer <token>. Eine Middleware auf dem Server liest diesen Header bei jeder Anfrage, prüft ihn und hängt den Nutzer an die Anfrage an.
Das Refresh-Token-Muster
Hier gibt es einen Zielkonflikt: Du möchtest, dass das Token kurzlebig ist (damit der Schaden bei Diebstahl gering bleibt), aber den Nutzer alle 15 Minuten zur erneuten Anmeldung zu zwingen, ist eine schlechte Erfahrung. Die Lösung sind zwei Tokens:
- Access-Token: kurzlebig (etwa 15 Minuten). Wird bei jeder API-Anfrage mitgeschickt.
- Refresh-Token: langlebig (etwa 7 Tage). Wird nur verwendet, um ein neues Access-Token zu erhalten.
Läuft das Access-Token ab, schickt der Client das Refresh-Token an den Server und erhält dafür ein frisches Access-Token — der Nutzer bemerkt nichts. Die wichtigen Sicherheitsdetails:
- Du musst das Refresh-Token serverseitig speichern (oder eine Sperrliste führen), damit "Abmelden" es wirklich widerrufen kann. Ein reines Access-Token ist zustandslos und bleibt daher gültig, bis es abläuft.
- Das Refresh-Token in einem HttpOnly-Cookie im Browser zu halten, verhindert, dass JavaScript es lesen und per XSS stehlen kann.
- Bei jeder Nutzung ein neues Refresh-Token auszustellen und das alte ungültig zu machen (Rotation), senkt das Diebstahlrisiko deutlich.
Häufige Fehler
- Geheimnisse in die Payload legen: Die Payload ist öffentlich, vergiss das nicht.
- Keine Ablaufzeit (
exp) setzen: Ein Token ohne Ablauf bleibt nach Diebstahl für immer gültig. alg: noneakzeptieren: Konfiguriere deine Bibliothek so, dass sie ausdrücklich angibt, welche Algorithmen sie akzeptiert.- Den geheimen Schlüssel fest einprogrammieren: Der Schlüssel gehört in eine Umgebungsvariable (
.env), nicht ins Repo.
Häufige Fragen
Ist ein JWT verschlüsselt?
Nein. Standardmäßig ist ein JWT signiert, nicht verschlüsselt. Sein Inhalt ist lesbar, kann aber nicht verändert werden. Willst du den Inhalt ebenfalls verbergen, ist JWE (JSON Web Encryption) ein eigener Standard — aber in den meisten Fällen ist es richtig, sensible Daten einfach gar nicht ins Token zu legen.
Wo soll ich das Token speichern?
Es gibt keine einzige perfekte Antwort. localStorage ist einfach, aber anfällig für XSS. Ein HttpOnly-Cookie ist gegen XSS geschützt, erfordert aber einen CSRF-Schutz. In Mobile-Apps bevorzugt man sichere Speicher (Keychain/Keystore).
Kann ich ein einzelnes JWT widerrufen?
Ein reines JWT ist zustandslos und kann daher nicht direkt widerrufen werden; es bleibt gültig, bis es abläuft. Brauchst du Widerruf, nutzt du ein kurzlebiges Access-Token plus ein serverseitiges Refresh-Token (Sperrliste).
Authentifizierung richtig aufzusetzen ist die Grundlage der Sicherheit eines Projekts. Wenn du Hilfe beim Aufsetzen eines JWT, eines Refresh-Token-Flows oder einer sicheren API-Architektur im Allgemeinen brauchst, nimm Kontakt mit mir auf — legen wir gemeinsam ein solides Fundament.