Was ist JWT und wie dekodiert man es sicher
JSON Web Tokens tauchen überall in der modernen Webentwicklung auf — Authentication Headers, OAuth-Flows, API-Schlüssel, Session-Management. Wenn Sie mit einer API gearbeitet haben, die ein Bearer-Token erfordert, haben Sie bereits ein JWT verwendet. Aber die meisten Entwickler behandeln sie als opake Blobs und schauen selten hinein. Das Verständnis der Struktur eines JWT, was jeder Teil bedeutet und wie man es ohne Sicherheitsfehler dekodiert, dauert etwa fünfzehn Minuten. Dieser Leitfaden behandelt alles.
Die Anatomie eines JWT
Jedes JWT ist eine Zeichenkette aus drei Base64URL-kodierten Segmenten, getrennt durch Punkte:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiZXhwIjoxNzQ3MDAwMDAwLCJpYXQiOjE3NDY5OTY0MDAsInNjb3BlIjoicmVhZDp1c2VycyJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c Das Format ist header.payload.signature. Jedes Segment kodiert unterschiedliche Informationen.
Der Header
Das erste Segment ist der Header. Dekodiert sieht das obige Beispiel so aus:
{
"alg": "RS256",
"typ": "JWT"
} alg gibt den zum Signieren des Tokens verwendeten Algorithmus an — RS256 bedeutet RSA mit SHA-256. typ identifiziert den Token-Typ. Diese beiden Felder sind das Minimum; einige Tokens enthalten auch kid (Key ID), um dem Verifizierer mitzuteilen, welchen öffentlichen Schlüssel er verwenden soll, wenn mehrere Schlüssel rotieren.
Der Payload
Das zweite Segment ist der Payload — die eigentlichen Daten. Dekodiert:
{
"sub": "user_123",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"exp": 1747000000,
"iat": 1746996400,
"scope": "read:users"
} Der Payload enthält Claims: Aussagen über die Entität, die das Token repräsentiert. Einige Claims sind standardisiert (sogenannte Registered Claims); andere sind anwendungsspezifisch (Private Claims). Der Payload ist Base64URL-kodiert, nicht verschlüsselt. Jeder, der die Token-Zeichenkette erhält, kann jeden Claim darin lesen.
Die Signatur
Das dritte Segment ist die Signatur. Sie wird erstellt, indem der kodierte Header und Payload zusammengenommen, mit einem Punkt verkettet und das Ergebnis mit dem in alg angegebenen Secret Key oder Private Key signiert wird:
signature = sign(
base64url(header) + "." + base64url(payload),
secretOrPrivateKey
) Die Signatur ermöglicht es jeder Partei mit dem entsprechenden öffentlichen Schlüssel (oder Secret Key bei symmetrischen Algorithmen) zu verifizieren, dass das Token von einer vertrauenswürdigen Quelle ausgestellt wurde und dass weder der Header noch der Payload nach der Ausstellung modifiziert wurde. Ein einzelnes geändertes Zeichen im Payload macht die Signatur vollständig ungültig.
Wie man ein JWT dekodiert
Dekodieren ist anders als verifizieren. Dekodieren liest einfach die Daten in einem Token. Verifizieren bestätigt, dass das Token authentisch und nicht abgelaufen ist. Sie sollten in Produktionscode immer verifizieren; Dekodieren allein ist nützlich für das Debugging.
Schritt 1: Token aufteilen
Teilen Sie die JWT-Zeichenkette am .-Zeichen auf. Sie erhalten drei Segmente. Wenn Sie weniger als drei erhalten, ist das Token fehlerhaft.
Schritt 2: Header und Payload dekodieren
Base64URL-dekodieren Sie jedes der ersten beiden Segmente. Base64URL ist wie Standard-Base64, verwendet aber - anstatt + und _ anstatt /, ohne Padding-Zeichen. Einmal dekodiert können Sie jedes Segment als JSON parsen.
Schritt 3: Parsen und inspizieren
Lesen Sie die Claims. Überprüfen Sie exp (Ablauf) gegen den aktuellen Unix-Timestamp. Schauen Sie auf iss und aud, um zu bestätigen, dass das Token für Ihre Anwendung bestimmt ist. Vertrauen Sie keinem Claim, bis Sie die Signatur verifiziert haben.
Für schnelle Inspektion während der Entwicklung verwenden Sie den JWT Decoder. Er läuft vollständig in Ihrem Browser — Ihr Token verlässt nie Ihr Gerät. Sie können Base64-Segmente auch manuell mit dem Base64-Kodierer/Dekodierer dekodieren, wenn Sie rohe Bytes sehen möchten. Zum Verifizieren von Signaturen in Test-Skripten können Sie mit dem HMAC Generator HS256-Signaturen reproduzieren, ohne Code zu schreiben.
Schritt 4: Signatur im Code verifizieren
In der Produktion immer die Signatur mit einer für Ihre Sprache entwickelten Bibliothek verifizieren. Implementieren Sie die Signaturverifizierung nicht von Hand. Beliebte Optionen sind jose oder jsonwebtoken für Node.js, PyJWT für Python, golang-jwt/jwt für Go und nimbus-jose-jwt für Java.
Geben Sie den Algorithmus immer explizit an. Lassen Sie die Bibliothek niemals den Algorithmus aus dem Token-Header ableiten.
Standard-Claims (Registered Claims)
RFC 7519 definiert eine Reihe von registrierten Claim-Namen. Diese sind nicht erforderlich, aber wenn sie vorhanden sind, müssen sie der Standardsemantik folgen.
iss — Aussteller (Issuer)
Die Entität, die das Token erstellt und signiert hat. Normalerweise eine URL, die den Autorisierungsserver identifiziert (z. B. https://auth.example.com). Verifizierer sollten prüfen, dass iss einem erwarteten Wert entspricht, und Tokens von unbekannten Ausstellern ablehnen.
sub — Subjekt (Subject)
Das Subjekt, das das Token repräsentiert — typischerweise eine Nutzer-ID, ein Service-Account-Name oder ein Gerätbezeichner. Der Wert muss im Kontext des Ausstellers eindeutig sein. Ihre Anwendung verwendet sub, um zu identifizieren, welchem Nutzer die Anfrage gehört.
aud — Zielgruppe (Audience)
Der beabsichtigte Empfänger des Tokens. Wenn der Bezeichner Ihrer API https://api.example.com ist, sollten für andere Services ausgestellte Tokens abgelehnt werden. Das Versäumnis, aud zu validieren, ermöglicht es Angreifern, ein von einem Service erhaltenes Token bei einem anderen Service wiederzuverwenden.
exp — Ablaufzeit (Expiration Time)
Ein Unix-Timestamp, nach dem das Token nicht mehr akzeptiert werden darf. Validieren Sie exp immer. Ein Token ohne Ablaufzeit lebt faktisch ewig — wenn es gestohlen wird, hat der Angreifer unbegrenzten Zugriff.
iat — Ausstellungszeit (Issued At)
Der Unix-Timestamp, wann das Token erstellt wurde. Nützlich zum Erkennen von Tokens, die technisch nicht abgelaufen, aber verdächtig alt sind. Sie können iat verwenden, um ein maximales Token-Alter unabhängig von exp durchzusetzen.
nbf — Nicht vor (Not Before)
Der Unix-Timestamp, vor dem das Token nicht akzeptiert werden darf. Seltener als exp, aber nützlich beim Ausstellen von Tokens im Voraus — z. B. ein geplanter Task, der erst zu einem bestimmten Zeitpunkt starten soll.
jti — JWT ID
Ein eindeutiger Bezeichner für das Token. Ermöglicht es Ausstellern, Token-Replay-Angriffe zu verhindern, indem verwendete jti-Werte gespeichert und Tokens mit doppelten IDs abgelehnt werden. Notwendig, wenn Sie Einmaltoken benötigen, wie z. B. Passwort-Reset-Links.
Sicherheitsfallstricke
JWT-Implementierungen haben eine Geschichte subtiler Schwachstellen. Das sind die wichtigsten, die Sie verstehen sollten, bevor Sie Code ausliefern, der JWTs akzeptiert.
Der "alg: none"-Angriff
Einige JWT-Bibliotheken aus den frühen Tagen des Standards akzeptierten ein Token, das "alg": "none" in seinem Header angab. Ein Angreifer konnte jedes gültige Token nehmen, den Algorithmus auf none ersetzen, die Signatur entfernen, und die Bibliothek würde es als vollständig gültig akzeptieren — keine Signatur erforderlich.
Die Abhilfe: Geben Sie beim Aufrufen Ihrer Verifizierungsfunktion immer den erwarteten Algorithmus explizit an. Behandeln Sie jedes Token, das alg: none beansprucht, als ungültig. Die meisten modernen Bibliotheken haben das behoben, aber es lohnt sich, die Standardeinstellungen Ihrer Bibliothek vor dem Go-Live zu bestätigen.
Algorithmus-Verwechslung (RS256 zu HS256 Downgrade)
Einige Bibliotheken, die beide Algorithmen unterstützten, verwendeten das alg-Feld im Token-Header, um zu entscheiden, wie verifiziert wird. Ein Angreifer könnte den Algorithmus auf HS256 ändern und das Token dann mit dem öffentlichen Schlüssel des Servers als HMAC-Secret signieren. Der Server würde beim Sehen von HS256 gegen den öffentlichen Schlüssel verifizieren und das gefälschte Token akzeptieren.
Die Abhilfe ist dieselbe: Sperren Sie den Algorithmus in Ihrem Verifizierungscode. Lassen Sie den Token-Header niemals beeinflussen, welcher Algorithmus für die Verifizierung verwendet wird.
Abgelaufene Tokens akzeptieren
Das Nicht-Validieren von exp ist ein häufiges Versäumnis — manchmal eingeführt, wenn Entwickler eine Toleranzperiode hinzufügen, die ohne Grenze wächst, oder wenn der Validierungscode-Pfad in einem Code-Branch umgangen wird. Behandeln Sie ein abgelaufenes Token genauso wie ein fehlendes Token: Lehnen Sie es mit einem 401 ab und fordern Sie den Client auf, sich erneut zu authentifizieren oder ein Refresh Token zu verwenden.
Sensible Daten im Payload
Der Payload ist Base64URL-kodiert, nicht verschlüsselt. Jeder, der das Token abfängt, kann es dekodieren. Legen Sie keine Passwörter, Kreditkartennummern, Sozialversicherungsnummern oder andere sensible Daten in den Payload. Wenn Sie sensible Claims sicher übertragen müssen, verwenden Sie ein JWE-(JSON Web Encryption-)Token, das den Payload verschlüsselt. Mit JWS signierte JWTs (der übliche Fall) garantieren nur Authentizität, nicht Vertraulichkeit.
Fehlende Audience-Validierung
Das Überspringen der aud-Validierung bedeutet, dass ein für Service A ausgestelltes Token bei Service B wiedergegeben werden kann — solange beide Services denselben Signing Key teilen oder demselben Aussteller vertrauen. Validieren Sie in Multi-Service-Architekturen immer, dass die Audience des Tokens mit dem Bezeichner Ihres Services übereinstimmt.
Best Practices für 2026
RS256 für die meisten Anwendungen wählen
RS256 verwendet einen privaten Schlüssel zum Signieren und einen öffentlichen Schlüssel zum Verifizieren. Nur der Autorisierungsserver hält den privaten Schlüssel. Jeder Service kann Tokens mit dem öffentlichen Schlüssel verifizieren, der offen veröffentlicht werden kann (oft über einen JWKS-Endpunkt). Wenn ein einzelner Service kompromittiert wird, erhalten Angreifer die Möglichkeit, Tokens zu verifizieren — aber nicht, neue zu fälschen.
HS256 verwendet ein einziges geteiltes Secret sowohl zum Signieren als auch zum Verifizieren. Jeder Service, der Tokens verifizieren kann, kann auch neue erstellen. In einer Microservice-Konfiguration erhöht das Teilen des Secrets über viele Services den Schadensradius einer Sicherheitsverletzung.
Access Tokens kurzlebig halten
Es gibt keinen eingebauten Widerrufsmechanismus für JWTs — einmal ausgestellt ist ein Token bis zum Ablauf gültig (es sei denn, Sie implementieren eine Blocklist, die server-seitigen State wieder einführt). Kurze Ablaufzeiten (15 Minuten bis 1 Stunde) begrenzen das Schadensfenster, wenn ein Token gestohlen wird. Kombinieren Sie Access Tokens mit langlebigen Refresh Tokens, die in sicheren HttpOnly-Cookies gespeichert werden, nicht in localStorage.
Refresh Token Rotation verwenden
Wenn ein Client ein Refresh Token verwendet, um ein neues Access Token zu erhalten, stellen Sie ein neues Refresh Token aus und invalidieren Sie das alte. Auf diese Weise wird ein gestohlenes Refresh Token beim nächsten Versuch des legitimen Clients erkannt, das Original zu verwenden: Der Server sieht ein wiederverwendetes Refresh Token und kann die gesamte Sitzung widerrufen. Dieses Muster ist in RFC 6819 beschrieben und wird von modernen Autorisierungsservern weitgehend unterstützt.
JWKS-Endpunkt veröffentlichen
Ein JSON Web Key Set (JWKS)-Endpunkt (/.well-known/jwks.json per Konvention) veröffentlicht Ihre Signing-Public-Keys in einem Standardformat. Andere Services können die JWKS abrufen und Tokens verifizieren, ohne Schlüssel out-of-band erhalten zu müssen. Das macht die Schlüsselrotation auch unkompliziert: Fügen Sie den neuen Schlüssel zur JWKS hinzu, beginnen Sie mit ihm zu signieren, dann entfernen Sie den alten Schlüssel, sobald alle bestehenden Tokens abgelaufen sind.
Schlüssel regelmäßig rotieren
Selbst wenn Ihr privater Schlüssel nie kompromittiert wird, begrenzt die regelmäßige Rotation von Schlüsseln das Fenster, in dem ein gestohlener Schlüssel zum Fälschen von Tokens verwendet werden könnte. Verwenden Sie kid in Ihren JWT-Headern, um den Signing-Key zu referenzieren, sodass Verifizierer während einer Rotation den richtigen öffentlichen Schlüssel aus Ihrer JWKS auswählen können, ohne bestehende Tokens zu brechen.
Jeden Claim validieren
Überprüfen Sie iss, aud, exp und nbf bei jeder Anfrage. Überspringen Sie keinen dieser Claims, weil sie in Ihrer Konfiguration redundant erscheinen — die Bedingungen, die sie heute redundant erscheinen lassen, sind genau die Bedingungen, die sich während eines Vorfalls ändern.
JWT vs. Session Cookies
JWTs und server-seitige Sessions lösen dasselbe Problem — das Persistieren des Authentifizierungsstatus über zustandsloses HTTP — aber mit unterschiedlichen Trade-offs.
JWTs sind selbstständig. Der Server muss keine Datenbank abfragen, um eine Anfrage zu validieren. Das macht sie attraktiv für verteilte Systeme und APIs, die von mobilen oder Drittanbieter-Clients genutzt werden. Der Nachteil ist, dass der Widerruf eine Blocklist erfordert (was server-seitigen State wieder einführt) oder das Tolerieren der verbleibenden Lebensdauer eines kompromittierten Tokens.
Session Cookies werden server-seitig validiert. Der Server speichert den Session-State und kann den Zugriff sofort durch Löschen der Session widerrufen. Cookies mit den Flags HttpOnly und Secure sind vor JavaScript-Zugriff und Netzwerkabhörung geschützt. Der Nachteil ist, dass jede Anfrage eine Datenbankabfrage erfordert, was bei großem Maßstab zum Engpass werden kann.
Für traditionelle Webanwendungen mit server-gerenderten Seiten und einem einzigen Backend bleiben Session Cookies eine solide und einfachere Wahl. Für APIs, die von mehreren Clients genutzt werden, Microservice-Architekturen und Mobile-Apps sind JWTs mit kurzer Ablaufzeit und Refresh-Token-Rotation die praktischere Option.
Ihr Token dekodieren
Der schnellste Weg, ein JWT zu inspizieren, ist es in den JWT Decoder einzufügen. Er teilt das Token auf, dekodiert den Header und Payload und rendert die Claims in einem lesbaren Format — alles ohne Ihr Token irgendwo zu senden. Wenn Sie rohe Base64URL-Zeichenketten manuell kodieren oder dekodieren müssen, verarbeitet der Base64-Kodierer/Dekodierer Standard- und URL-sichere Varianten. Zum Verifizieren von HMAC-Signaturen in Test-Skripten können Sie mit dem HMAC Generator eine HS256-Signatur reproduzieren und mit dem Inhalt Ihres Tokens vergleichen.
Die vollständige Spezifikation finden Sie in RFC 7519 (JWT) und den interaktiven Beispielen unter jwt.io.