Um ein JWT-Token zu dekodieren, teilen Sie die Zeichenfolge an den beiden Punkten in drei Teile und dekodieren Sie dann den Header und die Nutzlast mit Base64url. Die Nutzlast ist reines JSON, das jeder lesen kann, da ein JWT kodiert, nicht verschlüsselt ist. In JavaScript können Sie dies mit atob in einer Zeile erledigen, aber nur, nachdem Sie die Base64url-Zeichen korrigiert haben, die eine naive Dekodierung stören. Diese Anleitung zeigt genau, wie man ein JWT-Token von Hand dekodiert, die Falle, die die meisten Code-Schnipsel übersehen, und warum die Dekodierung nichts darüber aussagt, ob das Token echt ist.
Wenn Sie jemals ein Token irgendwo eingefügt haben und die Ansprüche sofort erschienen sind, ist das der Teil, der die Leute verwirrt. Beim Lesen eines JWT ist kein geheimer Schlüssel beteiligt. Die Sicherheit kommt von der Signatur, nicht vom Verstecken des Inhalts, und die Verwechslung dieser beiden Konzepte führt dazu, dass Entwickler echte Fehler ausliefern. Lassen Sie uns zuerst eines richtig dekodieren und dann das gefährliche Missverständnis dahinter klären.
Wie ein JWT tatsächlich aussieht#
Ein JSON Web Token ist eine einzelne Zeichenkette aus drei Teilen, die durch Punkte getrennt sind:
header.payload.signature
Ein echtes Token sieht so aus (hier für die Lesbarkeit umgebrochen, es ist eine durchgehende Zeichenkette):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNzE3NzI4MDAwLCJleHAiOjE3MTc3MzE2MDB9.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Jeder Teil hat eine Aufgabe:
- Header: ein winziges JSON-Objekt, das den Signaturalgorithmus (
alg) und den Tokentyp (typ) angibt. Base64url-kodiert. - Payload: das JSON-Objekt mit Ihren Claims (Benutzer-ID, Rollen, Ablaufdatum, alles, was Sie dort ablegen). Base64url-kodiert.
- Signatur: ein kryptografischer Hash von Header und Payload, berechnet mit einem geheimen oder privaten Schlüssel. Dies ist der einzige Teil, der beweist, dass das Token nicht manipuliert wurde.
Header und Payload sind nicht verborgen. Sie sind base64url-kodiert, was von jedem ohne Schlüssel umkehrbar ist. Behandeln Sie alles in einer JWT-Payload als öffentliche Information.
Warum base64url und nicht normales base64#
JWTs leben in URLs, HTTP-Headern und Cookies. Standard-base64 verwendet die Zeichen +, / und abschließende =-Padding, die in diesen Kontexten unsicher oder störend sind. Daher verwenden JWTs base64url, definiert in RFC 4648, das + durch -, / durch _ ersetzt und das =-Padding vollständig weglässt.
Dieser einzige Unterschied ist der Grund, warum die meisten Copy-Paste-Dekodierungs-Snippets bei echten Token scheitern. Wenn Sie eine Payload, die ein - oder _ enthält, base64-dekodieren, ohne sie vorher zu konvertieren, erhalten Sie verstümmelte Ausgabe oder einen Fehler. Das behandeln wir unten explizit. Wenn Sie die Kodierungsmechanik separat sehen möchten, können Sie mit unserem base64-Kodierer/Dekodierer mit Standard- versus URL-sicherer Ausgabe experimentieren.
So decodieren Sie ein JWT-Token in JavaScript#
Der Browser stellt Ihnen atob für die Base64-Decodierung zur Verfügung. Der Trick besteht darin, zuerst base64url wieder in standard Base64 umzuwandeln und dann Unicode korrekt zu behandeln. Hier ist die vollständige, korrekte Version, nicht der fehlerhafte Einzeiler, den man normalerweise findet.
Schritt 1: Teilen Sie das Token an den Punkten#
Das Token ist header.payload.signature. Teilen Sie es und greifen Sie die gewünschten Teile ab.
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIn0.signature_here";
const [headerB64, payloadB64, signatureB64] = token.split(".");
Wenn token.split(".") nicht genau drei Teile zurückgibt, ist der String kein wohlgeformtes JWT und Sie sollten hier aufhören, anstatt Müll zu decodieren.
Schritt 2: Konvertieren Sie base64url zurück in standard Base64#
Dies ist der Schritt, den fast jeder kurze Schnipsel auslässt, und genau deshalb brechen diese Schnipsel bei Produktionstokens, die - oder _ enthalten.
function base64UrlToBase64(input) {
// Ersetzen Sie URL-sichere Zeichen mit standard Base64-Zeichen
let output = input.replace(/-/g, "+").replace(/_/g, "/");
// Fügen Sie die Padding hinzu, die base64url entfernt hat
const pad = output.length % 4;
if (pad) {
output += "=".repeat(4 - pad);
}
return output;
}
Ohne Wiederherstellung des Paddings werfen einige Umgebungen einen InvalidCharacterError bei atob. Damit decodieren Sie jedes Mal zuverlässig.
Schritt 3: Decodieren Sie mit atob und parsen Sie das JSON#
Jetzt funktioniert atob, aber es gibt noch eine weitere Hürde. atob gibt einen binären String zurück, sodass alle Nicht-ASCII-Zeichen (akzentuierte Namen, Emojis, nicht-lateinische Schriften) verstümmelt werden. Decodieren Sie die Bytes als UTF-8, um sicher zu sein.
function decodeJwtPart(part) {
const base64 = base64UrlToBase64(part);
const binary = atob(base64);
// Konvertieren Sie den binären String in einen korrekten UTF-8-String
const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
const json = new TextDecoder("utf-8").decode(bytes);
return JSON.parse(json);
}
const header = decodeJwtPart(headerB64);
const payload = decodeJwtPart(payloadB64);
console.log(header); // { alg: "HS256", typ: "JWT" }
console.log(payload); // { sub: "1234567890", name: "Jane Doe", ... }
Schritt 4: Lesen Sie die für Sie relevanten Claims#
Das Payload ist jetzt ein normales JavaScript-Objekt. Greifen Sie die Standard-Claims ab:
console.log("Subject:", payload.sub);
console.log("Ausgestellt am:", new Date(payload.iat * 1000).toISOString());
console.log("Läuft ab am:", new Date(payload.exp * 1000).toISOString());
console.log("Abgelaufen?", payload.exp * 1000 < Date.now());
Beachten Sie, dass iat und exp Unix-Zeitstempel in Sekunden sind, multiplizieren Sie sie also mit 1000, bevor Sie sie an Date übergeben. Das Vergessen führt zu Zeitstempeln im Jahr 1970 und einem sehr verwirrenden Nachmittag.
Ein Hinweis zu Node.js#
In Node existiert atob in modernen Versionen, aber die idiomatische Decodierung verwendet Buffer, das base64url und UTF-8 in einem Schritt erledigt:
const payload = JSON.parse(
Buffer.from(payloadB64, "base64url").toString("utf8")
);
Das Encoding-Flag "base64url" erledigt den Zeichenaustausch und das Padding für Sie, weshalb Node-Code für diese Aufgabe sauberer aussieht als Browser-Code.
Dekodieren ist nicht Verifizieren: Der Fehler, der zu Sicherheitslücken führt#
Hier ist der Teil, vor dem die Code-Schnipsel nie warnen, und es ist das Wichtigste auf dieser Seite. Das Dekodieren eines JWT liest nur die Claims. Es bestätigt nicht, dass diese Claims wahr sind.
Jeder kann ein Token nehmen, die Nutzlast ändern (z.B. "role": "user" in "role": "admin" umwandeln), es neu kodieren und an Ihren Server zurückgeben. Die dekodierte Nutzlast sieht dann perfekt gültig aus. Das Einzige, was zwischen diesem gefälschten Token und Ihren Daten steht, ist die Signaturprüfung, die den geheimen oder öffentlichen Schlüssel erfordert und die das Dekodieren nie berührt.
| Aktion | Benötigt einen Schlüssel? | Was es beweist |
|---|---|---|
| Header/Nutzlast dekodieren | Nein | Was das Token behauptet |
| Signatur verifizieren | Ja | Dass das Token von Ihnen ausgestellt und unverändert ist |
exp / nbf prüfen | Nein (aber erst nach Verifikation) | Dass das Token innerhalb seines gültigen Zeitfensters liegt |
Die Regel ist einfach und absolut:
Vertrauen Sie niemals einer dekodierten JWT-Nutzlast, um eine Sicherheitsentscheidung zu treffen. Dekodieren Sie sie nur zur Anzeige und Fehlersuche. Auf dem Server müssen Sie immer die Signatur mit einer vertrauenswürdigen Bibliothek verifizieren, bevor Sie auf Basis eines einzigen Claims handeln.
Ein dekodiertes Token ist eine Behauptung, keine Tatsache. Die Nutzlast als gegeben zu behandeln, weil sie "richtig aussieht", ist genau der Weg, wie Privilegieneskalationsfehler in die Produktion gelangen. Für die vollständige Erklärung, warum dies zwei verschiedene Operationen sind und wo Teams Fehler machen, lesen Sie unseren Leitfaden zu Dekodieren vs. Verifizieren in der JWT-Sicherheit.
"Ist ein JWT verschlüsselt?" Nein, und das ist wichtig#
Dies ist das Missverständnis hinter den meisten JWT-Fehlern. Ein standardmäßig signiertes JWT (ein JWS) ist kodiert, nicht verschlüsselt. Die Nutzlast ist für jeden, der das Token abfängt, vollständig lesbar. Die Signatur schützt die Integrität (niemand kann sie unbemerkt ändern), nicht die Vertraulichkeit (jeder kann sie lesen).
Die praktischen Konsequenzen:
- Setzen Sie keine Geheimnisse in eine JWT-Nutzlast. Keine Passwörter, keine API-Schlüssel, keine persönlichen Daten, die Sie nicht auf eine Werbetafel drucken würden. Sie sind nur eine Base64url-Dekodierung entfernt vom Auslesen.
- Wenn Sie wirklich Vertraulichkeit benötigen, brauchen Sie JWE (JSON Web Encryption), ein anderes und weniger verbreitetes Format, das die Nutzlast tatsächlich verschlüsselt.
- Gehen Sie davon aus, dass jedes von Ihnen ausgestellte JWT überprüft wird. Logs, Browser-Entwicklertools, Proxys und jeder Dekodierer können es lesen.
Die Standardansprüche lesen#
Die Nutzlast kann alles enthalten, aber eine Reihe registrierter Ansprüche haben definierte Bedeutungen. Wenn Sie sie kennen, können Sie Authentifizierungsprobleme schnell beheben.
| Anspruch | Name | Bedeutung |
|---|---|---|
iss | Aussteller | Wer hat den Token erstellt und signiert |
sub | Betreff | Auf wen sich der Token bezieht, normalerweise eine Benutzer-ID |
aud | Zielgruppe | Für wen der Token bestimmt ist |
exp | Ablauf | Unix-Zeit (Sekunden), nach der der Token ungültig ist |
nbf | Nicht vor | Unix-Zeit, vor der der Token ungültig ist |
iat | Ausgestellt am | Unix-Zeit, zu der der Token erstellt wurde |
jti | JWT-ID | Eine eindeutige Kennung für den Token |
Wenn Sie einen Fehler suchen, warum ein Benutzer ausgeloggt wird, decodieren Sie den Token und prüfen Sie zuerst exp. Ein abgelaufenes exp oder ein Uhrenversatzproblem mit nbf ist der häufigste Übeltäter, und Sie können es in Sekunden erkennen, sobald die Nutzlast lesbar ist.
Wann Sie stattdessen ein Decoder-Tool verwenden sollten#
Das Schreiben der Decode-Funktion lohnt sich einmal, um die Funktionsweise zu verstehen. Für die tägliche Fehlersuche ist es jedoch langsam, jedes Mal eine Funktion in die Konsole einzufügen, und ein schlechtes Copy-Paste führt den gerade behobenen Base64url-Fehler wieder ein.
Ein browserbasierter Decoder ist schneller und sicherer für die Überprüfung:
- Er teilt, konvertiert und formatiert Header und Payload sofort.
- Er markiert eine abgelaufene
exp, sodass Sie die Zeitstempel-Berechnung nicht selbst durchführen müssen. - Er läuft in Ihrem Browser, sodass das Token nicht an einen Server gesendet wird (wichtig, da das Token eine aktive Berechtigung ist).
Dieser letzte Punkt ist wichtiger, als die meisten denken. Ein JWT ist oft ein aktives Sitzungstoken. Wenn Sie es in einen fragwürdigen Online-Decoder einfügen, der es an ein Backend sendet, geben Sie funktionierende Anmeldedaten weiter. Unser kostenloser JWT-Decoder dekodiert vollständig in Ihrem Browser, zeigt Header, Payload und ein lesbares Ablaufdatum an und überträgt das Token nirgendwohin. Für den Sicherheitskontext, was ein Decoder kann und was nicht, geht unser JWT-Decoder und Token-Sicherheitsleitfaden tiefer auf sichere Überprüfungsgewohnheiten ein.
So dekodieren Sie ein JWT-Token sicher: Die Zusammenfassung#
Um ein JWT-Token zu dekodieren, teilen Sie es an den Punkten, konvertieren Sie jeden base64url-Teil in standard base64 (ersetzen Sie - und _, fügen Sie Padding hinzu), führen Sie atob aus und parsen Sie das JSON. In Node erledigt Buffer.from(part, "base64url") die Konvertierung für Sie. Der Header verrät den Algorithmus, die Payload enthält Ihre Claims, und iat und exp sind Sekunden seit 1970.
Das Wichtigste, das Sie mitnehmen sollten: Dekodieren bedeutet Lesen, nicht Vertrauen. Eine JWT-Payload ist öffentlich, umkehrbar und fälschbar. Dekodieren Sie sie frei für Anzeige und Debugging, aber treffen Sie jede echte Autorisierungsentscheidung auf dem Server, nachdem Sie die Signatur mit einem Schlüssel verifiziert haben. Verstehen Sie diesen Unterschied, und JWTs sind einfach. Verwischen Sie ihn, und Sie haben ein Sicherheitsloch, das wie funktionierender Code aussieht.
Häufig gestellte Fragen#
Wie dekodiere ich ein JWT-Token ohne Bibliothek?
Teilen Sie das Token an den Punkten in Header, Payload und Signatur auf und dekodieren Sie dann Header und Payload mit base64url. Im Browser konvertieren Sie base64url in base64 (ersetzen Sie - durch +, _ durch / und fügen Sie =-Padding wieder hinzu), bevor Sie atob aufrufen, dann JSON.parse auf das Ergebnis anwenden. In Node erledigt Buffer.from(part, "base64url").toString("utf8") dies in einer Zeile.
Warum schlägt mein atob-Aufruf bei einem JWT fehl?
Weil JWTs base64url verwenden, nicht standardmäßiges base64. Sie enthalten - und _ anstelle von + und / und entfernen das =-Padding. Wenn Sie diesen Rohstring an atob übergeben, wird ein Fehler ausgegeben oder Müll zurückgegeben. Konvertieren Sie zuerst die Zeichen und stellen Sie das Padding wieder her, was der Schritt ist, den die meisten kurzen Code-Snippets auslassen.
Ist ein JWT verschlüsselt oder nur kodiert? Ein standardmäßig signiertes JWT ist kodiert, nicht verschlüsselt. Der Payload ist base64url, den jeder ohne Schlüssel umkehren kann. Behandeln Sie seinen Inhalt daher als öffentlich. Die Signatur schützt vor Manipulation, nicht vor Lesen. Wenn der Payload vertraulich sein muss, verwenden Sie stattdessen JWE (JSON Web Encryption).
Kann jemand meinen JWT-Payload lesen oder ändern? Jeder, der das Token besitzt, kann den Payload sofort lesen, da er nur base64url ist. Er kann ihn auch ändern und neu kodieren. Was er nicht tun kann, ist eine gültige Signatur ohne Ihren geheimen oder privaten Schlüssel zu erzeugen. Deshalb muss Ihr Server die Signatur überprüfen, anstatt den dekodierten Claims zu vertrauen.
Bestätigt das Dekodieren eines JWT, dass es gültig ist?
Nein. Dekodieren liest nur, was das Token behauptet. Die Verifikation ist ein separater Schritt, der die Signatur mit Ihrem Schlüssel prüft, um die Authentizität und Unverändertheit des Tokens zu bestätigen, und dann exp und nbf auf Timing prüft. Treffen Sie niemals eine Autorisierungsentscheidung allein auf Basis eines dekodierten Payloads.
Was bedeuten iat und exp in einem JWT?
Es sind Zeitstempel. iat (Issued At) ist der Zeitpunkt der Token-Erstellung, und exp (Expiration) ist der Zeitpunkt, ab dem es ungültig wird. Beide sind Unix-Zeit in Sekunden, also multiplizieren Sie mit 1000, bevor Sie ein JavaScript Date erstellen. Ein Token ist abgelaufen, wenn exp * 1000 kleiner als die aktuelle Zeit ist.



