JWT-Guides

So debugge ich eine ungültige JWT-Signatur

Meine Reihenfolge für falsche Schlüssel, Algorithmusprobleme, kid-Fehler, Rotation, HMAC-Encoding und veränderte Token-Bytes, ohne die Signaturprüfung abzuschalten.

Von JWTDecoder.toolsZuletzt geprüft 2026-09-16

Redaktionelle Stimme: Formulierungen in der ersten Person beschreiben den dokumentierten Workflow von JWTDecoder.tools; Herausgeber und Organisationsautor ist JWTDecoder.tools.

Ablauf zur Analyse einer ungültigen JWT-Signatur
Algorithmus, Issuer, kid und Schlüsselauswahl prüfen, bevor die Verifikation geändert wird.

Bei invalid signature, signature verification failed oder einer ungültigen JWT-Signatur ändere ich weder Payload noch Verifier-Konfiguration auf Verdacht. Ich sichere das originale kompakte Token und prüfe deterministisch: Algorithmus, exakte Key-Bytes, Issuer, kid, Rotation und erst dann Claims.

Mit bekanntem Secret/Public Key starte ich im JWT Signature Verifier. Bei JWKS nutze ich den JWKS Validator.

Was „invalid signature“ präzise bedeutet

Ein kompaktes JWS hat:

base64url(header).base64url(payload).base64url(signature)

Verifikation verwendet die original codierten ersten beiden Segmente. Wenn sie scheitert, stimmen mindestens Algorithmus, Schlüssel oder signierte Bytes nicht mit dem Signer überein.

Der Fehler sagt dagegen nicht automatisch etwas über exp, aud oder Berechtigungen aus.

Mein erster Split: HMAC oder asymmetrisch?

Header:

{ "alg": "HS256", "kid": "optional" }

oder:

{ "alg": "RS256", "kid": "prod-2026-09" }

Meine Diagnose verzweigt sofort:

HS256/384/512 -> Secret-Bytes, Encoding, Rotation
RS256/384/512 -> Public Key, PEM/JWK, kid, JWKS, Issuer

Ich lasse das Token nicht selbst die Policy festlegen. Die Anwendung hat eine Algorithmus-Allowlist.

HMAC: gleiche Zeichenfolge bedeutet nicht zwingend gleiche Bytes

Bei HS256 prüfe ich besonders:

  • UTF-8-Text vs. Base64-dekodiertes Secret;
  • verstecktes \n am Ende einer Environment Variable;
  • unterschiedliche Secrets in Dev/Prod;
  • Secret Rotation;
  • Copy/Paste mit Leerzeichen;
  • zu schwache, menschenlesbare Secrets.

Beispiel:

const raw = new TextEncoder().encode(process.env.JWT_SECRET);
const fromBase64 = Uint8Array.from(atob(process.env.JWT_SECRET), c => c.charCodeAt(0));
// raw und fromBase64 sind nicht dasselbe Key-Material.

Ich kläre zuerst, welche Interpretation der Signer verwendet.

RSA: PEM, Zertifikat und SPKI auseinanderhalten

Bei RS256 kann „falscher Key“ auch ein Formatproblem sein. Ich prüfe:

-----BEGIN PUBLIC KEY-----      -> häufig SPKI
-----BEGIN CERTIFICATE-----     -> X.509 Zertifikat
-----BEGIN RSA PUBLIC KEY-----  -> PKCS#1 Public Key

Libraries akzeptieren nicht jede Form identisch. Ich konvertiere kontrolliert statt Header/Footer blind zu löschen.

kid und JWKS als Auswahlproblem debuggen

Wenn der Token Header kid enthält, suche ich im vertrauenswürdigen JWKS des erwarteten Issuers. Häufige Ursachen:

  • kid fehlt im gecachten JWKS;
  • neuer Key wurde veröffentlicht, Cache ist alt;
  • alter Key wurde zu früh entfernt;
  • falscher Tenant/Issuer;
  • kid trifft auf inkompatiblen kty oder alg;
  • mehrere Keys erzeugen Ambiguität.

Der JWT-kid-Guide vertieft die Auswahl; der Key-Rotation-Guide den Lifecycle.

Exakte Fehlertexte richtig zuordnen

Typische Library-Meldungen sind:

JsonWebTokenError: invalid signature
JWSSignatureVerificationFailed
signature verification failed
InvalidSignatureError
kid not found
no applicable key found in the JSON Web Key Set

kid not found ist streng genommen noch vor der Kryptografie ein Key-Selection-Fehler. Ich werfe ihn nicht in denselben Topf wie eine tatsächlich berechnete, aber falsche Signatur.

Warum Re-Encoding einen Vergleich zerstören kann

Ich verifiziere das Originaltoken. Ich dekodiere nicht JSON, serialisiere es „schön“ neu und erwarte dieselbe Signatur.

Diese Payloads können semantisch gleich aussehen:

{"sub":"42","role":"user"}
{ "role": "user", "sub": "42" }

aber unterschiedliche Bytes erzeugen. JWS signiert Bytes des compact serialization input, nicht die semantische Bedeutung eines JSON-Objekts.

Eine gültige Signatur ist erst der Anfang der Acceptance

Wenn die Signatur passt, prüfe ich weiterhin:

  • exp / nbf;
  • erwarteten iss;
  • erwarteten aud;
  • Token-Typ;
  • anwendungsspezifische Scopes/Rollen.

Dafür nutze ich den JWT Validator oder JWT Debugger.

Was ich niemals als „Fix“ akzeptiere

  • Verification ausschalten;
  • beliebigen Algorithmus aus dem Header akzeptieren;
  • Key von einer untrusted jku/URL laden und automatisch vertrauen;
  • Payload editieren und alte Signatur weiterverwenden;
  • beim ersten kid-Treffer alle Metadaten ignorieren;
  • weak HMAC Secret wählen, nur damit beide Seiten denselben String kennen.

Meine Entscheidungsmatrix

SymptomWahrscheinliche SchichtPrüfen
HS256 invalid signatureSecret/Encodingexakte Bytes, Base64, Newline
RS256 invalid signaturePublic Key/FormatIssuer-Key, PEM/JWK
kid not foundAuswahl/CacheJWKS, Rotation, Environment
Algorithm mismatchPolicyerlaubter alg, Key-Typ
nach Payload-Edit Fehlersigned bytesOriginaltoken verwenden
Signatur ok, trotzdem 401Claimsexp/iss/aud/Token-Typ

Mein Invalid-Signature-Workflow

  1. Ich sichere das originale compact JWT unverändert.
  2. Ich dekodiere Header alg und kid sowie Payload iss.
  3. Ich bestätige die erlaubte Algorithmus-Policy der Anwendung.
  4. Ich bestimme die vertrauenswürdige Key-Quelle für diesen Issuer.
  5. Bei HMAC vergleiche ich die exakten Secret-Bytes und deren Encoding.
  6. Bei RSA/EC prüfe ich Key-Format, Key-Typ und Provenienz.
  7. Bei JWKS prüfe ich kid, Cache und Rotation.
  8. Ich verifiziere über die originalen header.payload-Bytes.
  9. Erst nach erfolgreicher Signatur prüfe ich Zeit, Issuer und Audience.
  10. Ich behebe die falsche Key-/Policy-/Deployment-Schicht, nicht die Sicherheitsprüfung.

Invalid signature ist ein Vertrauensfehler, kein kosmetischer Parsing-Fehler. Genau diese Trennung macht die Diagnose reproduzierbar.

Quellen und Referenzen

Verwandte Guides