lib/rodauth/features/oauth_jwt_base.rb in rodauth-oauth-1.4.0 vs lib/rodauth/features/oauth_jwt_base.rb in rodauth-oauth-1.5.0

- old
+ new

@@ -165,10 +165,14 @@ def jwk_thumbprint(jwk) jwk = jwk_import(jwk) if jwk.is_a?(Hash) jwk.thumbprint end + def private_jwk?(jwk) + %w[d p q dp dq qi].any?(&jwk.method(:key?)) + end + def jwt_encode(payload, jwks: nil, headers: {}, encryption_algorithm: oauth_jwt_jwe_keys.keys.dig(0, 0), encryption_method: oauth_jwt_jwe_keys.keys.dig(0, 1), @@ -220,10 +224,11 @@ jwe_key: oauth_jwt_jwe_keys[[jws_encryption_algorithm, jws_encryption_method]] || oauth_jwt_jwe_keys.values.first, verify_claims: true, verify_jti: true, verify_iss: true, verify_aud: true, + verify_headers: nil, ** ) jws_key = jws_key.first if jws_key.is_a?(Array) if jwe_key @@ -270,10 +275,12 @@ (verify_jti && !verify_jti(claims[:jti], claims)) ) return end + return if verify_headers && !verify_headers.call(claims.header) + claims rescue JSON::JWT::Exception nil end @@ -331,10 +338,14 @@ def jwk_thumbprint(jwk) jwk = jwk_import(jwk) if jwk.is_a?(Hash) JWT::JWK::Thumbprint.new(jwk).generate end + def private_jwk?(jwk) + jwk_import(jwk).private? + end + def jwt_encode(payload, signing_algorithm: oauth_jwt_keys.keys.first, headers: {}, **) key = oauth_jwt_keys[signing_algorithm] || _jwt_key @@ -392,11 +403,12 @@ jws_algorithm: oauth_jwt_public_keys.keys.first || oauth_jwt_keys.keys.first, jws_key: oauth_jwt_keys[jws_algorithm] || _jwt_key, verify_claims: true, verify_jti: true, verify_iss: true, - verify_aud: true + verify_aud: true, + verify_headers: nil ) jws_key = jws_key.first if jws_key.is_a?(Array) # verifying the JWT implies verifying: # @@ -419,36 +431,38 @@ else {} end # decode jwt - claims = if is_authorization_server? - if jwks - jwks = jwks[:keys] if jwks.is_a?(Hash) + claims, headers = if is_authorization_server? + if jwks + jwks = jwks[:keys] if jwks.is_a?(Hash) - # JWKs may be set up without a KID, when there's a single one - if jwks.size == 1 && !jwks[0][:kid] - key = jwks[0] - algo = key[:alg] - key = JWT::JWK.import(key).keypair - JWT.decode(token, key, true, algorithms: [algo], **verify_claims_params).first - else - algorithms = jws_algorithm ? [jws_algorithm] : jwks.select { |k| k[:use] == "sig" }.map { |k| k[:alg] } - JWT.decode(token, nil, true, algorithms: algorithms, jwks: { keys: jwks }, **verify_claims_params).first - end - elsif jws_key - JWT.decode(token, jws_key, true, algorithms: [jws_algorithm], **verify_claims_params).first - else - JWT.decode(token, jws_key, false, **verify_claims_params).first - end - elsif (jwks = auth_server_jwks_set) - algorithms = jwks[:keys].select { |k| k[:use] == "sig" }.map { |k| k[:alg] } - JWT.decode(token, nil, true, jwks: jwks, algorithms: algorithms, **verify_claims_params).first - end + # JWKs may be set up without a KID, when there's a single one + if jwks.size == 1 && !jwks[0][:kid] + key = jwks[0] + algo = key[:alg] + key = JWT::JWK.import(key).keypair + JWT.decode(token, key, true, algorithms: [algo], **verify_claims_params) + else + algorithms = jws_algorithm ? [jws_algorithm] : jwks.select { |k| k[:use] == "sig" }.map { |k| k[:alg] } + JWT.decode(token, nil, true, algorithms: algorithms, jwks: { keys: jwks }, **verify_claims_params) + end + elsif jws_key + JWT.decode(token, jws_key, true, algorithms: [jws_algorithm], **verify_claims_params) + else + JWT.decode(token, jws_key, false, **verify_claims_params) + end + elsif (jwks = auth_server_jwks_set) + algorithms = jwks[:keys].select { |k| k[:use] == "sig" }.map { |k| k[:alg] } + JWT.decode(token, nil, true, jwks: jwks, algorithms: algorithms, **verify_claims_params) + end return if verify_claims && verify_aud && !verify_aud(claims["aud"], claims["client_id"]) + return if verify_headers && !verify_headers.call(headers) + claims rescue JWT::DecodeError, JWT::JWKError nil end @@ -500,9 +514,13 @@ def jwt_encode(_token) raise "#{__method__} is undefined, redefine it or require either \"jwt\" or \"json-jwt\"" end def jwt_decode(_token, **) + raise "#{__method__} is undefined, redefine it or require either \"jwt\" or \"json-jwt\"" + end + + def private_jwk?(_jwk) raise "#{__method__} is undefined, redefine it or require either \"jwt\" or \"json-jwt\"" end # :nocov: end end