Skip to content
ecdsa.com
ruby-jwt (Ruby)Ruby

Error message

Signature verification failed (JWT::VerificationError)

Also printed as

  • JWT::VerificationError: Signature verification failed

Uncaught, Ruby prints the location followed by "Signature verification failed (JWT::VerificationError)"; the text is the same in ruby-jwt 2.10 and 3.3.

ruby-jwt (Ruby) — JWT::VerificationError from JWT.decode

What it means

ruby-jwt decoded the token and checked its signature with the key you passed, and the check failed. The token is well formed and the algorithm is allowed; the key does not belong to the signer, or the token was altered. `JWT::VerificationError` is a subclass of `JWT::DecodeError`, so `rescue JWT::DecodeError` catches it together with malformed-token errors.

Why it happens

How to fix it

  1. 1.

    Select keys by kid from the issuer's JWKS

    The `jwks:` option accepts a loader; ruby-jwt calls it again with `kid_not_found: true` when the token names an unknown key, so rotations are picked up.

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

    Prove the keys match

    Identical hashes of the public halves rule out the key; then look for modifications of the token in transit.

    bash
    openssl pkey -in issuer-private.pem -pubout | sha256sum
    openssl pkey -pubin -in configured-public.pem | sha256sum   # must be identical

Related errors

Browse the full signature error database