Перейти к содержимому
ecdsa.com
golang-jwt/jwt (Go)Go

Сообщение об ошибке

token signature is invalid: crypto/ecdsa: verification error

Также выводится как

  • 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 возвращает только внутренний текст, например «crypto/ecdsa: verification error». Вместо сравнения строк используйте `errors.Is(err, jwt.ErrTokenSignatureInvalid)` (v5).

golang-jwt/jwt (Go) — jwt.ErrTokenSignatureInvalid joined with the algorithm's verification error

Что это означает

golang-jwt разобрал токен, принял его алгоритм и получил ключ от вашей `Keyfunc`, но подпись не прошла проверку этим ключом. В v5 ошибка объединяет `jwt.ErrTokenSignatureInvalid` («token signature is invalid») с собственной ошибкой алгоритма: `crypto/ecdsa: verification error` для ES*, `crypto/rsa: verification error` для RS*/PS*, `signature is invalid` для HS*. Байты токена и ключ просто не соответствуют друг другу.

Почему это происходит

Как исправить

  1. 1.

    Выбирайте ключ из JWKS по kid

    Пусть Keyfunc выбирает из набора ключей издателя ключ, указанный в заголовке токена, и обновляет набор при ротации (например, с помощью `github.com/MicahParks/keyfunc`). Всегда явно задавайте `WithValidMethods`.

    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. 2.

    Убедитесь, что обе стороны используют один и тот же ключ

    Вычислите хеш открытого ключа в кодировке DER на проверяющей стороне и хеш открытой половины закрытого ключа издателя. Если хеши различаются, расследование на этом закончено.

    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. 3.

    Обрабатывайте класс ошибки, а не строку

    golang-jwt v5 экспортирует предопределённые ошибки (sentinel errors). Отвечайте на ошибку подписи статусом 401 и не переходите к перебору других ключей или пропуску проверки.

    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
    }

Связанные ошибки

Открыть всю базу ошибок подписей