require "jwt" # gem install jwt -v 3.3.0require "json"require "openssl" # PEM -> JWK: export without the generated kid, public members onlyjwk = JWT::JWK.new(OpenSSL::PKey.read(File.read("pub.pem")))public_jwk = jwk.export.except(:kid)File.write("out.jwk.json", JSON.generate(public_jwk))puts JSON.generate(public_jwk) # JWK -> PEM: import the JWK, take the OpenSSL key, write SPKI PEMkey = JWT::JWK.import(JSON.parse(File.read("pub.jwk.json"))).verify_keyFile.write("out.pem", key.public_to_pem)print key.public_to_pemHow it works
OpenSSL::PKey.readloads the PEM;JWT::JWK.new(key)wraps it as a JWK object for EC, RSA or HMAC keys.exportreturns a hash with symbol keys —:kty,:crv,:x,:yand a generated:kid— and never the private members unless asked.JWT::JWK.import(hash)reads a JWK;verify_keyis the OpenSSL public key, built and checked by OpenSSL.public_to_pemwrites the SPKI PEM, identical to the original file.
Gotchas
exportadds akidthe gem computes itself (its key digest, not the RFC 7638 thumbprint);except(:kid)removes it, or setkid_generator_type = :rfc7638_thumbprintto get a standard one.export(include_private: true)addsd; the default export is public only.- An off-curve point fails when the key is built:
OpenSSL::PKey::EC::Point::Error: EC_POINT_bn2point: point is not on curve. - Ed25519 (OKP) JWKs are not supported by the gem (
JWT::UnsupportedKeyType); for those,OpenSSL::PKey.new_raw_public_key("ED25519", raw)andraw_public_keydo the conversion.