Wenn ich ein JWT bekomme und zunächst nur wissen möchte, was darin steht, suche ich nicht sofort nach einem Signing Secret. Bei einem normalen signierten JWT/JWS mit drei Segmenten sind Header und Payload Base64URL-kodiert, nicht verschlüsselt. Zum Lesen brauche ich daher kein Secret.
Die Grenze halte ich bewusst fest: Decode zeigt mir, was das Token behauptet; Verify zeigt mir, ob ein bereits vertrauenswürdiger Schlüssel diese Bytes signiert hat; Validate entscheidet, ob meine Anwendung das Token akzeptieren darf.
Für die erste Sichtung nutze ich den JWT Decoder.
Zuerst prüfe ich 3 Segmente gegen 5 Segmente
Ein signiertes JWS sieht typischerweise so aus:
header.payload.signature
Ein compact JWE hat üblicherweise fünf Segmente. Sehe ich fünf, erwarte ich nicht, dass Base64URL allein die Claims offenlegt. JWE ist verschlüsselt; Dekodierung und Entschlüsselung sind unterschiedliche Aufgaben.
Warum ich ohne Secret lesen kann
Header und Payload sind JSON in Base64URL-Darstellung. Base64URL ist Encoding, keine Verschlüsselung.
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-2026-09"
}
{
"sub": "user_123",
"iss": "https://auth.example.com/",
"aud": "api://backend",
"iat": 1789000000,
"exp": 1789003600
}
Die Signatur schützt Integrität und Authentizität. Sie macht die normalen Claims nicht vertraulich.
Was ich nach dem Decode zuerst lese
alg— welcher Algorithmus wird behauptet?kid— welcher Key-Identifier soll später bei der Auswahl helfen?iss— welcher Issuer wird behauptet?aud— für welchen Empfänger ist das Token gedacht?exp,nbf,iat— passt das Zeitfenster?scope,roles,groups— welche Autorisierungsdaten sind vorhanden?sub— welcher Subject-Identifier ist enthalten?
Die JWT-Claims-Anleitung geht tiefer. In dieser Phase behandle ich alles weiterhin als untrusted input.
Warum ich einen lesbaren Payload nicht vertraue
Jeder kann JSON erzeugen, Base64URL-kodieren und eine JWT-ähnliche Zeichenfolge bauen.
{ "role": "user" }
kann zu:
{ "role": "admin" }
geändert und weiterhin dekodiert werden. Was ohne autorisiertes Schlüsselmaterial nicht möglich sein sollte, ist eine neue Signatur, die ein korrekt konfigurierter Verifier akzeptiert.
Darum bedeutet „decoded successfully“ für mich nie „valid JWT“.
Wann ich Secret oder Public Key brauche
Sobald meine Frage von „Was steht drin?“ zu „Hat der vertrauenswürdige Signer genau diese Bytes signiert?“ wechselt.
Bei HS256 brauche ich das korrekte Shared Secret. Bei RS256 brauche ich normalerweise den Public Key des Issuers, nicht dessen Private Key.
Mit vertrauenswürdigem Material nutze ich den JWT Signature Verifier, bei JWKS den JWKS Validator.
Decode, Verify und Validate bleiben getrennt
Decode
Header, Payload, Timestamps und Signature-Segment lesen.
Verify
Kryptografisch mit einem Schlüssel prüfen, dessen Herkunft bereits vertrauenswürdig ist.
Validate
iss, aud, exp, nbf, Token-Typ, Scopes und Rollen mit der Application Policy vergleichen.
Wenn Zeit die wahrscheinliche Ursache ist
JWT NumericDate verwendet Sekunden. JavaScript Date.now() verwendet Millisekunden.
Für iat, nbf und exp nutze ich den JWT Expiry Checker. Liegt exp noch in der Zukunft und die API liefert 401, gehe ich zu Issuer, Audience und Signature weiter.
Umgang mit Production Bearer Tokens
Auch lesbare Access Tokens bleiben Credentials.
Ich:
- setze JWTs nicht in URLs;
- logge keine vollständigen Bearer Tokens;
- bevorzuge synthetische oder redigierte Tokens;
- teile keine Refresh Tokens, Private Keys oder HMAC Secrets;
- sende ein Token nicht an einen Server, nur um Base64URL zu dekodieren.
JWTDecoder.tools verarbeitet den Decoder im Browser-Speicher. Das schützt jedoch nicht vor Malware, Extensions oder Clipboard-Tools auf dem Gerät.
Meine Checkliste
- 3-Segment-JWS oder 5-Segment-JWE bestimmen.
- Header/Payload als Base64URL + UTF-8 JSON lesen.
alg,kid,iss,audund Zeit-Claims prüfen.- Claims bis zur Signaturprüfung als untrusted behandeln.
- Bei Zeitproblemen JWT Expiry Checker verwenden.
- Für Authentizität JWT Signature Verifier oder JWKS Validator verwenden.
- Bei weiterem 401 Issuer/Audience im JWT Debugger vergleichen.
Meine praktische Regel lautet: Zum Lesen eines normalen signierten JWT brauche ich kein Secret. Um den gelesenen Claims zu vertrauen, brauche ich aber einen vertrauenswürdigen Verification Path.