Fehlermeldung
signature verification failed
jose (JavaScript) — JWSSignatureVerificationFailed, code ERR_JWS_SIGNATURE_VERIFICATION_FAILED
Was der Fehler bedeutet
jose hat die JWS erfolgreich geparst und die kryptografische Prüfung ausgeführt, aber die Signatur lässt sich mit dem ausgewählten Schlüssel nicht bestätigen. Struktur, Algorithmus und Schlüsseltyp waren alle in Ordnung – die Mathematik ging schlicht nicht auf, was auf den Schlüssel oder auf veränderte signierte Bytes hinweist.
Warum der Fehler auftritt
Falscher Schlüssel für dieses Token
häufigDer Prüfer hat einen anderen Schlüssel als den, mit dem der Aussteller signiert hat: ein rotiertes JWKS, aus dem der alte kid verschwunden ist, ein fest im Code hinterlegter Schlüssel, der veraltet ist, oder eine Verwechslung der Umgebungen (Prüfer im Staging, Token aus der Produktion).
Signierte Bytes haben sich zwischen Signierer und Prüfer verändert
häufigJWS signiert exakt den base64url-Text von header.payload. Alles, was diese Segmente neu kodiert – ein Gateway, das das base64-Padding normalisiert, eine erneute JSON-Serialisierung, beim Transport abgeschnittene Zeichen –, lässt die Prüfung scheitern, auch wenn die dekodierte Payload identisch aussieht.
Selbst gebauter ES256-Signierer hat DER erzeugt
gelegentlichcrypto.sign() von Node gibt für ECDSA standardmäßig ASN.1 DER aus, RFC 7518 verlangt für ES256-JWS-Signaturen aber rohes r‖s (genau 64 Byte). Ein Token, dessen drittes Segment dekodiert ~70–72 Byte ergibt und mit 0x30 beginnt, wurde im falschen Format signiert.
So behebst du den Fehler
- 1.
Schlüssel per kid aus dem JWKS des Ausstellers ermitteln
Lass jose für jedes Token den richtigen Schlüssel auswählen, statt per Pinning von Hand einen einzigen festzulegen; createRemoteJWKSet speichert Schlüssel zwischen und aktualisiert sie über Rotationen hinweg.
js import { createRemoteJWKSet, jwtVerify } from "jose"; const jwks = createRemoteJWKSet(new URL("https://issuer.example/.well-known/jwks.json")); const { payload } = await jwtVerify(token, jwks, { algorithms: ["ES256"], issuer: "https://issuer.example", }); - 2.
Wenn du mit node:crypto signierst: rohes r‖s ausgeben
Fordere bei eigenen Signierern eine Ausgabe nach IEEE P1363 an, damit die Signatur im 64-Byte-Format vorliegt, das JWS verlangt – oder prüfe anhand der Länge des dritten Segments, was dein Signierer erzeugt hat.
js import { sign } from "node:crypto"; const sig = sign("sha256", Buffer.from(signingInput), { key: privateKey, dsaEncoding: "ieee-p1363", // raw r||s, 64 bytes for P-256 }); - 3.
Form des Signatursegments prüfen
Dekodiere das dritte Segment des Tokens: 64 Byte bedeuten rohes r‖s (korrekt für ES256), ~70 Byte mit 0x30 am Anfang bedeuten DER. Der Konverter DER ⇄ Raw unten zeigt die Werte r und s und wandelt zwischen beiden Formaten um.