jwtdecoder.de

Ratgeber · JWT 2026

JWT debuggen: typische Fehler und schnelle Fixes

Wie man Token-Probleme schnell isoliert: Header decodieren, Algorithmus prüfen, exp/nbf gegen Server-Uhrzeit, Secret-Encoding (UTF-8 vs Base64).

Foto von Mateusz Viola

Von Mateusz Viola

Betreiber & redaktionelle Verantwortung jwtdecoder.de

Acht typische Fälle

Beim Arbeiten mit JWT tauchen immer wieder die gleichen Probleme auf. Folgende Liste hilft, Token-Bugs schnell zu isolieren.

1. "Invalid Signature" trotz richtigem Secret

Häufigste Ursache: Secret-Encoding-Mismatch. HMAC braucht Bytes - aber wie der String-zu-Bytes-Konvert läuft, ist library-spezifisch.

  • UTF-8: einfach "my-secret" als UTF-8 interpretieren
  • Base64: "bXktc2VjcmV0" erst base64-decoden, dann als Bytes nutzen
  • Hex: "6d792d736563726574" als Hex parsen

Wenn Issuer das Secret als base64 hat und Verifier als UTF-8 interpretiert: Mismatch. Beide Seiten müssen das gleiche Encoding nutzen.

Tipp: Secrets immer als base64-encoded random bytes erzeugen (openssl rand -base64 32), Library mit base64-Decode konfigurieren.

2. "Token expired" obwohl gerade ausgestellt

Clock-Skew zwischen Servern. Issuer-Uhr ist 30 s vor, Verifier-Uhr ist normal. Issuer setzt exp = jetzt + 60 s, das landet beim Verifier als "vor 30 s abgelaufen".

Lösung: NTP-Sync auf allen Servern, Clock-Skew-Toleranz beim Verifier (±60 s ist Standard), exp-Lifetime nicht zu kurz wählen (mindestens 5 min, besser 10).

3. exp/iat sind Sekunden, nicht Millisekunden

JavaScript Date.now() liefert Millisekunden, JWT erwartet Sekunden. Häufiger Bug:

// FALSCH
const exp = Date.now() + 600 * 1000;  // Millisekunden

// RICHTIG
const exp = Math.floor(Date.now() / 1000) + 600;  // Sekunden

Mit Millisekunden gesetzt ist exp ein Wert in der fernen Zukunft (Jahr 2049+) - Token läuft 1000x später ab als gewollt. Mit Millisekunden bei Verify gegen Sekunden interpretiert ist exp "schon vor Jahrtausenden abgelaufen". Beides ist falsch.

4. Token-Whitespace beim Kopieren

Wer ein Token aus einem Email, Slack oder Browser-DevTools kopiert, kopiert oft Zeilenumbrüche, Leerzeichen oder unsichtbare Unicode-Zeichen mit. Base64url ist strikt - schon ein Leerzeichen am Ende macht die Signaturprüfung kaputt.

Tipp: vor dem Pasten trim() oder im Decoder visuell prüfen, ob das Token nur aus den Zeichen A-Z a-z 0-9 - _ . besteht.

5. alg-Header passt nicht zum Verifier

Issuer signiert mit HS256, Verifier konfiguriert ist für RS256. Library lehnt das Token ab, der Fehler kann unspezifisch sein ("Invalid Signature").

Tipp: ersten Schritt im Debugging: Header im JWT Decoder anschauen, alg-Wert prüfen. Mit Verifier-Erwartung abgleichen.

6. ECDSA-Signatur-Format-Konflikt

JOSE-Standard (RFC 7518) verlangt für ECDSA-Signaturen das raw R||S-Konkatenat: bei ES256 sind das 64 byte (R: 32 byte, S: 32 byte).

OpenSSL und viele Crypto-Libraries (Node.js's crypto, Java's java.security) liefern ECDSA-Signaturen aber als ASN.1-DER: variable Länge, ~70 byte.

Wer ein JWT mit OpenSSL-erzeugter Signatur baut, ohne sie in raw R||S zu konvertieren, produziert ein Token, das von JOSE-konformen Libraries abgelehnt wird. Library-spezifische Helper sind nötig.

7. Token in Base64, nicht Base64url

JWT verwendet base64url (RFC 4648 §5): Zeichen -_ statt +/, kein Padding. Wer mit klassischem base64 encodiert (mit +/=), produziert ein Token, das URL-Transport problematisch macht und das einige Libraries nicht parsen können.

Library-API auf base64url-Variante prüfen (in Node.js: Buffer.toString('base64url'), in Python: urlsafe_b64encode).

8. JWKS-Cache vergiftet

Verifier hat JWKS gecached, aber Issuer hat den Key rotiert. Neue Tokens haben kid, der im Cache nicht steht → "Key not found".

Lösung: JWKS-Cache-TTL korrekt setzen (typisch 1-6 h), bei kid-Miss einmal frisch nachladen. Siehe Key-Rotation.

Allgemeines Debugging-Vorgehen

  1. Token in jwtdecoder.de einfügen: Header und Payload werden als JSON gezeigt. Daraus alle wichtigen Infos ablesen - alg, kid, exp, iss, aud.
  2. exp-Check: Decoder zeigt automatisch ob abgelaufen.
  3. Signatur-Verifikation: mit dem erwarteten Secret/Public Key im Decoder testen. Falls Decoder grünen Badge zeigt, aber Production-Verifier ablehnt: das Problem liegt im Verifier-Code, nicht im Token.
  4. Server-Log: Verifier-Library hat meist sehr spezifische Error-Codes (e.g. "SignatureMismatchException"). Die exakte Exception ist wichtig - "Invalid Token" ist zu generisch.
  5. Vergleich zu Working-Token: ein bekannt-funktionierendes Token vom selben Issuer holen, Side-by-Side im Decoder ansehen. Welche Felder unterscheiden sich?

Test-Tokens für Lokal-Debugging

Im JWT Decoder kann man Test-Tokens direkt selbst signieren - Tab "Erstellen", Header und Payload editieren, Algorithmus und Secret wählen. Praktisch um schnell ein Token mit spezifischen Claims zu erzeugen und gegen den eigenen Verifier zu werfen.

Standard-Test-JWTs (klassisches jwt.io-Beispiel) sind nützlich als Smoke-Test:

// HS256 mit secret "your-256-bit-secret"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Mehr zum Thema