Сообщение об ошибке
Signature verification failed (JWT::VerificationError)
Также выводится как
- JWT::VerificationError: Signature verification failed
Если исключение не перехвачено, Ruby выводит место, где возникла ошибка, а за ним — «Signature verification failed (JWT::VerificationError)»; текст одинаков в ruby-jwt 2.10 и 3.3.
ruby-jwt (Ruby) — JWT::VerificationError from JWT.decode
Что это означает
ruby-jwt декодировал токен и проверил его подпись переданным ключом, но проверка не прошла. Токен корректно сформирован, алгоритм разрешён, а ключ не принадлежит подписанту или токен изменили. `JWT::VerificationError` — подкласс `JWT::DecodeError`, поэтому `rescue JWT::DecodeError` перехватывает её вместе с ошибками некорректного токена.
Почему это происходит
Ключ в настройках не принадлежит подписанту
частоОткрытый ключ из другого окружения, устаревший ключ после ротации или пара ключей, которая заново генерируется при каждом запуске в конфигурации для разработки, по ошибке попавшей в рабочее окружение.
Проверка не тем ключом из JWKS
иногдаБрать `keys.first` из JWKS издателя можно, пока издатель не начнёт подписывать другим ключом. Пусть ruby-jwt выбирает ключ по `kid`: для этого есть параметр `jwks:`.
Разные секреты HMAC
иногдаПриложения Rails часто выводят секрет из `secret_key_base`; сервис, который использует другое значение — или то же значение, но с переводом строки в конце, — вычисляет другой MAC.
Как исправить
- 1.
Выбирайте ключи по kid из JWKS издателя
Параметр `jwks:` принимает загрузчик; если в токене указан неизвестный ключ, ruby-jwt вызывает загрузчик повторно с `kid_not_found: true`, поэтому ротация ключей подхватывается.
ruby require "jwt" require "net/http" jwks_loader = ->(options) do @jwks = nil if options[:kid_not_found] && @jwks_loaded_at.to_i < Time.now.to_i - 300 # refetch on rotation @jwks ||= begin @jwks_loaded_at = Time.now.to_i JSON.parse(Net::HTTP.get(URI("https://issuer.example.com/.well-known/jwks.json"))) end end payload, header = JWT.decode(token, nil, true, algorithms: ["ES256"], jwks: jwks_loader, iss: "https://issuer.example.com/", verify_iss: true) - 2.
Убедитесь, что ключи совпадают
Если хеши открытых половин совпадают, ключ ни при чём; тогда ищите изменения токена при передаче.
bash openssl pkey -in issuer-private.pem -pubout | sha256sum openssl pkey -pubin -in configured-public.pem | sha256sum # must be identical