require "jwt" # gem install jwt -v 3.3.0require "json"require "openssl" # From a JWK file%w[ec.jwk.json rsa.jwk.json].each do |file| jwk = JWT::JWK.import(JSON.parse(File.read(file))) puts "#{file}: #{JWT::JWK::Thumbprint.new(jwk)}"end # From a PEM public key%w[ec.pub.pem rsa.pub.pem].each do |file| jwk = JWT::JWK.new(OpenSSL::PKey.read(File.read(file))) puts "#{file}: #{JWT::JWK::Thumbprint.new(jwk)}"end # Ed25519 (OKP) is not supported by the gem: hash the RFC 8037 members, already in sorted orderokp = JSON.parse(File.read("okp.jwk.json")).slice("crv", "kty", "x")puts "okp.jwk.json: #{[OpenSSL::Digest::SHA256.digest(JSON.generate(okp))].pack("m0").tr("+/", "-_").delete("=")}" # The gem's default kid is NOT the RFC 7638 thumbprint unless configured soputs "default kid: #{JWT::JWK.new(OpenSSL::PKey.read(File.read("ec.pub.pem"))).kid}"JWT.configuration.jwk.kid_generator_type = :rfc7638_thumbprintputs "rfc7638 kid: #{JWT::JWK.new(OpenSSL::PKey.read(File.read("ec.pub.pem"))).kid}"How it works
JWT::JWK.import(hash)builds a JWK from parsed JSON;JWT::JWK.new(pkey)from an OpenSSL key read from PEM.JWT::JWK::Thumbprint.new(jwk).to_ssorts the required members, serializes them and returns the base64url SHA-256 digest.- Every JWK object gets a
kidwhen created;kid_generator_type = :rfc7638_thumbprintmakes thatkidthe RFC 7638 thumbprint. - The thumbprint is the same for the JWK and for the PEM form of the key, as the run shows. For Ed25519, which the gem does not support,
slice("crv", "kty", "x")keeps the RFC 8037 members in sorted order andJSON.generatewrites them without whitespace.
Gotchas
- The gem's default
kidis its own key digest (kid_generator_type = :key_digest), not the RFC 7638 thumbprint — the run prints a different value. Other libraries do not compute it; switch the generator before publishing keys. - The configuration is global: setting
JWT.configuration.jwk.kid_generator_typeaffects every JWK created afterwards in the process, as the secondkidabove shows. - OKP keys are not supported:
JWT::JWK.importof an Ed25519 JWK raisesJWT::UnsupportedKeyType: Key type OKP not supported— hence the hand-built canonical form above.Hash#slicereturns the keys in the order they are listed, which is why they are listed sorted. - An imported JWK keeps the
kidfrom the JSON; the generator only fills in a missing one.