Fehlermeldung
token signature is invalid: crypto/ecdsa: verification error
Auch ausgegeben als
- token signature is invalid: crypto/rsa: verification error
- token signature is invalid: signature is invalid
- token signature is invalid: ed25519: verification error
- crypto/ecdsa: verification error
golang-jwt v4 gibt nur den inneren Text zurück, etwa „crypto/ecdsa: verification error“. Verwende `errors.Is(err, jwt.ErrTokenSignatureInvalid)` (v5), statt Strings zu vergleichen.
golang-jwt/jwt (Go) — jwt.ErrTokenSignatureInvalid joined with the algorithm's verification error
Was der Fehler bedeutet
golang-jwt hat das Token geparst, seinen Algorithmus akzeptiert und von deiner `Keyfunc` einen Schlüssel erhalten, aber die Signaturprüfung mit diesem Schlüssel ist fehlgeschlagen. In v5 verknüpft der Fehler `jwt.ErrTokenSignatureInvalid` („token signature is invalid“) mit dem eigenen Fehler des Algorithmus: `crypto/ecdsa: verification error` bei ES*, `crypto/rsa: verification error` bei RS*/PS*, `signature is invalid` bei HS*. Die Bytes des Tokens und der Schlüssel gehören schlicht nicht zusammen.
Warum der Fehler auftritt
Die Keyfunc gibt den falschen Schlüssel zurück
häufigEin Schlüssel aus einer anderen Umgebung, ein fest im Code hinterlegter Schlüssel aus einer Dokumentation oder eine Keyfunc, die `kid` ignoriert und immer den ersten Schlüssel eines Schlüsselsatzes mit mehreren Schlüsseln zurückgibt.
Der Aussteller hat seinen Signaturschlüssel rotiert
häufigDienste, die einen öffentlichen Schlüssel einmal beim Start laden, prüfen nach einer Rotation weiter mit dem alten Schlüssel. Jedes neue Token scheitert, während ältere zwischengespeicherte Tokens noch durchgehen, bis der Dienst den Schlüssel neu lädt.
Der Signierer hat eine DER-kodierte ECDSA-Signatur erzeugt
gelegentlichgolang-jwt erwartet ES256-Signaturen als 64 Byte im Rohformat (r‖s, RFC 7518). Ein Token, das von einem KMS oder mit `ecdsa.SignASN1` ohne Konvertierung signiert wurde, trägt eine DER-Signatur von etwa 71 Byte, deren Prüfung selbst mit dem richtigen Schlüssel fehlschlägt.
Das Token wurde nach dem Signieren verändert
gelegentlichNeu kodierte Payloads, geänderter Whitespace im Header- oder Payload-Segment oder ein Token, das aus Teilen zweier verschiedener Tokens zusammengesetzt wurde. Die Signatur deckt exakt den base64url-Text ab.
So behebst du den Fehler
- 1.
Schlüssel per kid aus dem JWKS ermitteln
Lass die Keyfunc den im Header des Tokens genannten Schlüssel aus dem Schlüsselsatz des Ausstellers auswählen und den Schlüsselsatz bei einer Rotation aktualisieren (zum Beispiel mit `github.com/MicahParks/keyfunc`). Lege immer `WithValidMethods` fest.
go import ( "context" "github.com/MicahParks/keyfunc/v3" "github.com/golang-jwt/jwt/v5" ) // Resolve the verification key from the issuer's JWKS by the token's kid. k, err := keyfunc.NewDefaultCtx(ctx, []string{"https://issuer.example.com/.well-known/jwks.json"}) if err != nil { return err } token, err := jwt.Parse(raw, k.Keyfunc, jwt.WithValidMethods([]string{"ES256"}), jwt.WithIssuer("https://issuer.example.com/"), jwt.WithAudience("https://api.example.com")) - 2.
Nachweisen, dass beide Seiten denselben Schlüssel verwenden
Bilde den Hash des DER-kodierten öffentlichen Schlüssels, den die prüfende Seite verwendet, und den Hash der öffentlichen Hälfte des privaten Schlüssels des Ausstellers. Unterschiedliche Hashes beenden die Untersuchung.
bash # Same key on both sides? Compare SPKI fingerprints. openssl pkey -pubin -in verifier-public.pem -outform DER | sha256sum openssl pkey -in issuer-private.pem -pubout -outform DER | sha256sum - 3.
Fehlerklasse behandeln, nicht den String
golang-jwt v5 stellt Sentinel-Fehler bereit. Bilde eine fehlgeschlagene Signaturprüfung auf 401 ab und weiche nicht darauf aus, andere Schlüssel zu probieren oder die Prüfung zu überspringen.
go switch { case errors.Is(err, jwt.ErrTokenSignatureInvalid): return http.StatusUnauthorized // wrong key or tampered token: never retry with another key blindly case errors.Is(err, jwt.ErrTokenExpired): return http.StatusUnauthorized // client should refresh case errors.Is(err, jwt.ErrTokenMalformed): return http.StatusBadRequest }