nov / openid_connect

OpenID Connect Server & Client Library
MIT License
417 stars 122 forks source link

Make it easier to support verification with HS256 #61

Closed stanhu closed 2 years ago

stanhu commented 3 years ago

Right now, OpenIDConnect::ResponseObject::IdToken.decode assumes public-key encryption and does not make it possible to verify a token signed with a HS256 using a shared-secret:

        def decode(jwt_string, key)
          if key == :self_issued
            decode_self_issued jwt_string
          else
            new JSON::JWT.decode jwt_string, key
          end
        end

The problem here is that we don't actually know whether we should be passing in a the set of public keys or whether the private key is correct. If the JWT is signed with HS256, providing a set of RSA keys (via JSON::JWK::Set) will either result in:

The caller can call JSON::JWT.decode to do this, but it seems better to put this logic in OpenIDConnect::ResponseObject::IdToken to avoid needing to do two decodings.

To fix this, we need to peek at the decoded JWT header to figure out whether to use the public or private key.

Maybe this library should provide a method to do this:

def decode_with_key(jwt_string, &block)
  decoded = JSON::JWT.decode(jwt_string, :skip_verification)
  key = yield(decoded.header)
  decoded.verify!(key)
end

This touches on some of the points raised in https://github.com/nov/openid_connect/issues/42.