jwt 2.9.2 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -16
  3. data/README.md +153 -83
  4. data/lib/jwt/base64.rb +3 -0
  5. data/lib/jwt/claims/audience.rb +10 -0
  6. data/lib/jwt/claims/crit.rb +35 -0
  7. data/lib/jwt/claims/decode_verifier.rb +3 -3
  8. data/lib/jwt/claims/expiration.rb +10 -0
  9. data/lib/jwt/claims/issued_at.rb +7 -0
  10. data/lib/jwt/claims/issuer.rb +10 -0
  11. data/lib/jwt/claims/jwt_id.rb +10 -0
  12. data/lib/jwt/claims/not_before.rb +10 -0
  13. data/lib/jwt/claims/numeric.rb +22 -0
  14. data/lib/jwt/claims/required.rb +10 -0
  15. data/lib/jwt/claims/subject.rb +10 -0
  16. data/lib/jwt/claims/verification_methods.rb +20 -0
  17. data/lib/jwt/claims/verifier.rb +6 -7
  18. data/lib/jwt/claims.rb +6 -14
  19. data/lib/jwt/claims_validator.rb +5 -2
  20. data/lib/jwt/configuration/container.rb +20 -0
  21. data/lib/jwt/configuration/decode_configuration.rb +24 -0
  22. data/lib/jwt/configuration/jwk_configuration.rb +1 -0
  23. data/lib/jwt/configuration.rb +8 -0
  24. data/lib/jwt/decode.rb +28 -68
  25. data/lib/jwt/deprecations.rb +1 -0
  26. data/lib/jwt/encode.rb +17 -56
  27. data/lib/jwt/encoded_token.rb +139 -0
  28. data/lib/jwt/error.rb +34 -0
  29. data/lib/jwt/json.rb +1 -1
  30. data/lib/jwt/jwa/compat.rb +3 -0
  31. data/lib/jwt/jwa/ecdsa.rb +3 -6
  32. data/lib/jwt/jwa/eddsa.rb +7 -6
  33. data/lib/jwt/jwa/hmac.rb +2 -3
  34. data/lib/jwt/jwa/hmac_rbnacl.rb +1 -0
  35. data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +1 -0
  36. data/lib/jwt/jwa/none.rb +1 -0
  37. data/lib/jwt/jwa/ps.rb +2 -3
  38. data/lib/jwt/jwa/rsa.rb +2 -3
  39. data/lib/jwt/jwa/signing_algorithm.rb +3 -0
  40. data/lib/jwt/jwa/unsupported.rb +1 -0
  41. data/lib/jwt/jwa/wrapper.rb +1 -0
  42. data/lib/jwt/jwa.rb +11 -3
  43. data/lib/jwt/jwk/ec.rb +2 -3
  44. data/lib/jwt/jwk/hmac.rb +2 -3
  45. data/lib/jwt/jwk/key_base.rb +1 -0
  46. data/lib/jwt/jwk/key_finder.rb +1 -0
  47. data/lib/jwt/jwk/kid_as_key_digest.rb +1 -0
  48. data/lib/jwt/jwk/okp_rbnacl.rb +3 -4
  49. data/lib/jwt/jwk/rsa.rb +2 -3
  50. data/lib/jwt/jwk/set.rb +2 -0
  51. data/lib/jwt/jwk.rb +1 -0
  52. data/lib/jwt/token.rb +112 -0
  53. data/lib/jwt/verify.rb +7 -0
  54. data/lib/jwt/version.rb +33 -10
  55. data/lib/jwt.rb +16 -0
  56. metadata +8 -4
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  # Deprecations module to handle deprecation warnings in the gem
5
+ # @api private
5
6
  module Deprecations
6
7
  class << self
7
8
  def context
data/lib/jwt/encode.rb CHANGED
@@ -2,68 +2,29 @@
2
2
 
3
3
  require_relative 'jwa'
4
4
 
5
- # JWT::Encode module
6
5
  module JWT
7
- # Encoding logic for JWT
6
+ # The Encode class is responsible for encoding JWT tokens.
8
7
  class Encode
8
+ # Initializes a new Encode instance.
9
+ #
10
+ # @param options [Hash] the options for encoding the JWT token.
11
+ # @option options [Hash] :payload the payload of the JWT token.
12
+ # @option options [Hash] :headers the headers of the JWT token.
13
+ # @option options [String] :key the key used to sign the JWT token.
14
+ # @option options [String] :algorithm the algorithm used to sign the JWT token.
9
15
  def initialize(options)
10
- @payload = options[:payload]
11
- @key = options[:key]
12
- @algorithm = JWA.resolve(options[:algorithm])
13
- @headers = options[:headers].transform_keys(&:to_s)
16
+ @token = Token.new(payload: options[:payload], header: options[:headers])
17
+ @key = options[:key]
18
+ @algorithm = options[:algorithm]
14
19
  end
15
20
 
21
+ # Encodes the JWT token and returns its segments.
22
+ #
23
+ # @return [String] the encoded JWT token.
16
24
  def segments
17
- validate_claims!
18
- combine(encoded_header_and_payload, encoded_signature)
19
- end
20
-
21
- private
22
-
23
- def encoded_header
24
- @encoded_header ||= encode_header
25
- end
26
-
27
- def encoded_payload
28
- @encoded_payload ||= encode_payload
29
- end
30
-
31
- def encoded_signature
32
- @encoded_signature ||= encode_signature
33
- end
34
-
35
- def encoded_header_and_payload
36
- @encoded_header_and_payload ||= combine(encoded_header, encoded_payload)
37
- end
38
-
39
- def encode_header
40
- encode_data(@headers.merge(@algorithm.header(signing_key: @key)))
41
- end
42
-
43
- def encode_payload
44
- encode_data(@payload)
45
- end
46
-
47
- def signature
48
- @algorithm.sign(data: encoded_header_and_payload, signing_key: @key)
49
- end
50
-
51
- def validate_claims!
52
- return unless @payload.is_a?(Hash)
53
-
54
- Claims.verify_payload!(@payload, :numeric)
55
- end
56
-
57
- def encode_signature
58
- ::JWT::Base64.url_encode(signature)
59
- end
60
-
61
- def encode_data(data)
62
- ::JWT::Base64.url_encode(JWT::JSON.generate(data))
63
- end
64
-
65
- def combine(*parts)
66
- parts.join('.')
25
+ @token.verify_claims!(:numeric)
26
+ @token.sign!(algorithm: @algorithm, key: @key)
27
+ @token.jwt
67
28
  end
68
29
  end
69
30
  end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ # Represents an encoded JWT token
5
+ #
6
+ # Processing an encoded and signed token:
7
+ #
8
+ # token = JWT::Token.new(payload: {pay: 'load'})
9
+ # token.sign!(algorithm: 'HS256', key: 'secret')
10
+ #
11
+ # encoded_token = JWT::EncodedToken.new(token.jwt)
12
+ # encoded_token.verify_signature!(algorithm: 'HS256', key: 'secret')
13
+ # encoded_token.payload # => {'pay' => 'load'}
14
+ class EncodedToken
15
+ include Claims::VerificationMethods
16
+
17
+ # Returns the original token provided to the class.
18
+ # @return [String] The JWT token.
19
+ attr_reader :jwt
20
+
21
+ # Initializes a new EncodedToken instance.
22
+ #
23
+ # @param jwt [String] the encoded JWT token.
24
+ # @raise [ArgumentError] if the provided JWT is not a String.
25
+ def initialize(jwt)
26
+ raise ArgumentError, 'Provided JWT must be a String' unless jwt.is_a?(String)
27
+
28
+ @jwt = jwt
29
+ @encoded_header, @encoded_payload, @encoded_signature = jwt.split('.')
30
+ end
31
+
32
+ # Returns the decoded signature of the JWT token.
33
+ #
34
+ # @return [String] the decoded signature.
35
+ def signature
36
+ @signature ||= ::JWT::Base64.url_decode(encoded_signature || '')
37
+ end
38
+
39
+ # Returns the encoded signature of the JWT token.
40
+ #
41
+ # @return [String] the encoded signature.
42
+ attr_reader :encoded_signature
43
+
44
+ # Returns the decoded header of the JWT token.
45
+ #
46
+ # @return [Hash] the header.
47
+ def header
48
+ @header ||= parse_and_decode(@encoded_header)
49
+ end
50
+
51
+ # Returns the encoded header of the JWT token.
52
+ #
53
+ # @return [String] the encoded header.
54
+ attr_reader :encoded_header
55
+
56
+ # Returns the payload of the JWT token.
57
+ #
58
+ # @return [Hash] the payload.
59
+ def payload
60
+ @payload ||= decode_payload
61
+ end
62
+
63
+ # Sets or returns the encoded payload of the JWT token.
64
+ #
65
+ # @return [String] the encoded payload.
66
+ attr_accessor :encoded_payload
67
+
68
+ # Returns the signing input of the JWT token.
69
+ #
70
+ # @return [String] the signing input.
71
+ def signing_input
72
+ [encoded_header, encoded_payload].join('.')
73
+ end
74
+
75
+ # Verifies the signature of the JWT token.
76
+ #
77
+ # @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.
78
+ # @param key [String, Array<String>] the key(s) to use for verification.
79
+ # @param key_finder [#call] an object responding to `call` to find the key for verification.
80
+ # @return [nil]
81
+ # @raise [JWT::VerificationError] if the signature verification fails.
82
+ # @raise [ArgumentError] if neither key nor key_finder is provided, or if both are provided.
83
+ def verify_signature!(algorithm:, key: nil, key_finder: nil)
84
+ raise ArgumentError, 'Provide either key or key_finder, not both or neither' if key.nil? == key_finder.nil?
85
+
86
+ key ||= key_finder.call(self)
87
+
88
+ return if valid_signature?(algorithm: algorithm, key: key)
89
+
90
+ raise JWT::VerificationError, 'Signature verification failed'
91
+ end
92
+
93
+ # Checks if the signature of the JWT token is valid.
94
+ #
95
+ # @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.
96
+ # @param key [String, Array<String>] the key(s) to use for verification.
97
+ # @return [Boolean] true if the signature is valid, false otherwise.
98
+ def valid_signature?(algorithm:, key:)
99
+ Array(JWA.resolve_and_sort(algorithms: algorithm, preferred_algorithm: header['alg'])).any? do |algo|
100
+ Array(key).any? do |one_key|
101
+ algo.verify(data: signing_input, signature: signature, verification_key: one_key)
102
+ end
103
+ end
104
+ end
105
+
106
+ alias to_s jwt
107
+
108
+ private
109
+
110
+ def decode_payload
111
+ raise JWT::DecodeError, 'Encoded payload is empty' if encoded_payload == ''
112
+
113
+ if unencoded_payload?
114
+ verify_claims!(crit: ['b64'])
115
+ return parse_unencoded(encoded_payload)
116
+ end
117
+
118
+ parse_and_decode(encoded_payload)
119
+ end
120
+
121
+ def unencoded_payload?
122
+ header['b64'] == false
123
+ end
124
+
125
+ def parse_and_decode(segment)
126
+ parse(::JWT::Base64.url_decode(segment || ''))
127
+ end
128
+
129
+ def parse_unencoded(segment)
130
+ parse(segment)
131
+ end
132
+
133
+ def parse(segment)
134
+ JWT::JSON.parse(segment)
135
+ rescue ::JSON::ParserError
136
+ raise JWT::DecodeError, 'Invalid segment encoding'
137
+ end
138
+ end
139
+ end
data/lib/jwt/error.rb CHANGED
@@ -1,23 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
+ # The EncodeError class is raised when there is an error encoding a JWT.
4
5
  class EncodeError < StandardError; end
6
+
7
+ # The DecodeError class is raised when there is an error decoding a JWT.
5
8
  class DecodeError < StandardError; end
9
+
10
+ # The RequiredDependencyError class is raised when a required dependency is missing.
6
11
  class RequiredDependencyError < StandardError; end
7
12
 
13
+ # The VerificationError class is raised when there is an error verifying a JWT.
8
14
  class VerificationError < DecodeError; end
15
+
16
+ # The ExpiredSignature class is raised when the JWT signature has expired.
9
17
  class ExpiredSignature < DecodeError; end
18
+
19
+ # The IncorrectAlgorithm class is raised when the JWT algorithm is incorrect.
10
20
  class IncorrectAlgorithm < DecodeError; end
21
+
22
+ # The ImmatureSignature class is raised when the JWT signature is immature.
11
23
  class ImmatureSignature < DecodeError; end
24
+
25
+ # The InvalidIssuerError class is raised when the JWT issuer is invalid.
12
26
  class InvalidIssuerError < DecodeError; end
27
+
28
+ # The UnsupportedEcdsaCurve class is raised when the ECDSA curve is unsupported.
13
29
  class UnsupportedEcdsaCurve < IncorrectAlgorithm; end
30
+
31
+ # The InvalidIatError class is raised when the JWT issued at (iat) claim is invalid.
14
32
  class InvalidIatError < DecodeError; end
33
+
34
+ # The InvalidAudError class is raised when the JWT audience (aud) claim is invalid.
15
35
  class InvalidAudError < DecodeError; end
36
+
37
+ # The InvalidSubError class is raised when the JWT subject (sub) claim is invalid.
16
38
  class InvalidSubError < DecodeError; end
39
+
40
+ # The InvalidCritError class is raised when the JWT crit header is invalid.
41
+ class InvalidCritError < DecodeError; end
42
+
43
+ # The InvalidJtiError class is raised when the JWT ID (jti) claim is invalid.
17
44
  class InvalidJtiError < DecodeError; end
45
+
46
+ # The InvalidPayload class is raised when the JWT payload is invalid.
18
47
  class InvalidPayload < DecodeError; end
48
+
49
+ # The MissingRequiredClaim class is raised when a required claim is missing from the JWT.
19
50
  class MissingRequiredClaim < DecodeError; end
51
+
52
+ # The Base64DecodeError class is raised when there is an error decoding a Base64-encoded string.
20
53
  class Base64DecodeError < DecodeError; end
21
54
 
55
+ # The JWKError class is raised when there is an error with the JSON Web Key (JWK).
22
56
  class JWKError < DecodeError; end
23
57
  end
data/lib/jwt/json.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require 'json'
4
4
 
5
5
  module JWT
6
- # JSON wrapper
6
+ # @api private
7
7
  class JSON
8
8
  class << self
9
9
  def generate(data)
@@ -2,7 +2,10 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Provides backwards compatibility for algorithms
6
+ # @api private
5
7
  module Compat
8
+ # @api private
6
9
  module ClassMethods
7
10
  def from_algorithm(algorithm)
8
11
  new(algorithm)
data/lib/jwt/jwa/ecdsa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # ECDSA signing algorithm
5
6
  class Ecdsa
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -13,9 +14,7 @@ module JWT
13
14
  def sign(data:, signing_key:)
14
15
  curve_definition = curve_by_name(signing_key.group.curve_name)
15
16
  key_algorithm = curve_definition[:algorithm]
16
- if alg != key_algorithm
17
- raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} signing key was provided"
18
- end
17
+ raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} signing key was provided" if alg != key_algorithm
19
18
 
20
19
  asn1_to_raw(signing_key.dsa_sign_asn1(digest.digest(data)), signing_key)
21
20
  end
@@ -23,9 +22,7 @@ module JWT
23
22
  def verify(data:, signature:, verification_key:)
24
23
  curve_definition = curve_by_name(verification_key.group.curve_name)
25
24
  key_algorithm = curve_definition[:algorithm]
26
- if alg != key_algorithm
27
- raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} verification key was provided"
28
- end
25
+ raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} verification key was provided" if alg != key_algorithm
29
26
 
30
27
  verification_key.dsa_verify_asn1(digest.digest(data), raw_to_asn1(signature, verification_key))
31
28
  rescue OpenSSL::PKey::PKeyError
data/lib/jwt/jwa/eddsa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the EdDSA family of algorithms
5
6
  class Eddsa
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -10,17 +11,17 @@ module JWT
10
11
  end
11
12
 
12
13
  def sign(data:, signing_key:)
13
- unless signing_key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey)
14
- raise_encode_error!("Key given is a #{signing_key.class} but has to be an RbNaCl::Signatures::Ed25519::SigningKey")
15
- end
14
+ raise_sign_error!("Key given is a #{signing_key.class} but has to be an RbNaCl::Signatures::Ed25519::SigningKey") unless signing_key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey)
15
+
16
+ Deprecations.warning('Using Ed25519 keys is deprecated and will be removed in a future version of ruby-jwt. Please use the ruby-eddsa gem instead.')
16
17
 
17
18
  signing_key.sign(data)
18
19
  end
19
20
 
20
21
  def verify(data:, signature:, verification_key:)
21
- unless verification_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey)
22
- raise_decode_error!("key given is a #{verification_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey")
23
- end
22
+ raise_verify_error!("key given is a #{verification_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey") unless verification_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey)
23
+
24
+ Deprecations.warning('Using Ed25519 keys is deprecated and will be removed in a future version of ruby-jwt. Please use the ruby-eddsa gem instead.')
24
25
 
25
26
  verification_key.verify(signature, data)
26
27
  rescue RbNaCl::CryptoError
data/lib/jwt/jwa/hmac.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the HMAC family of algorithms
5
6
  class Hmac
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -20,9 +21,7 @@ module JWT
20
21
 
21
22
  OpenSSL::HMAC.digest(digest.new, signing_key, data)
22
23
  rescue OpenSSL::HMACError => e
23
- if signing_key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
24
- raise_verify_error!('OpenSSL 3.0 does not support nil or empty hmac_secret')
25
- end
24
+ raise_verify_error!('OpenSSL 3.0 does not support nil or empty hmac_secret') if signing_key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
26
25
 
27
26
  raise e
28
27
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the HMAC family of algorithms (using RbNaCl)
5
6
  class HmacRbNaCl
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the HMAC family of algorithms (using RbNaCl prior to a certain version)
5
6
  class HmacRbNaClFixed
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
data/lib/jwt/jwa/none.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the none algorithm
5
6
  class None
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
data/lib/jwt/jwa/ps.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the RSASSA-PSS family of algorithms
5
6
  class Ps
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -11,9 +12,7 @@ module JWT
11
12
  end
12
13
 
13
14
  def sign(data:, signing_key:)
14
- unless signing_key.is_a?(::OpenSSL::PKey::RSA)
15
- raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance.")
16
- end
15
+ raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance.") unless signing_key.is_a?(::OpenSSL::PKey::RSA)
17
16
 
18
17
  signing_key.sign_pss(digest_algorithm, data, salt_length: :digest, mgf1_hash: digest_algorithm)
19
18
  end
data/lib/jwt/jwa/rsa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the RSA family of algorithms
5
6
  class Rsa
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -11,9 +12,7 @@ module JWT
11
12
  end
12
13
 
13
14
  def sign(data:, signing_key:)
14
- unless signing_key.is_a?(OpenSSL::PKey::RSA)
15
- raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance")
16
- end
15
+ raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance") unless signing_key.is_a?(OpenSSL::PKey::RSA)
17
16
 
18
17
  signing_key.sign(digest, data)
19
18
  end
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
+ # JSON Web Algorithms
4
5
  module JWA
6
+ # Base functionality for signing algorithms
5
7
  module SigningAlgorithm
8
+ # Class methods for the SigningAlgorithm module
6
9
  module ClassMethods
7
10
  def register_algorithm(algo)
8
11
  ::JWT::JWA.register_algorithm(algo)
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Represents an unsupported algorithm
5
6
  module Unsupported
6
7
  class << self
7
8
  include JWT::JWA::SigningAlgorithm
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # @api private
5
6
  class Wrapper
6
7
  include SigningAlgorithm
7
8
 
data/lib/jwt/jwa.rb CHANGED
@@ -18,9 +18,7 @@ require_relative 'jwa/rsa'
18
18
  require_relative 'jwa/unsupported'
19
19
  require_relative 'jwa/wrapper'
20
20
 
21
- if JWT.rbnacl?
22
- require_relative 'jwa/eddsa'
23
- end
21
+ require_relative 'jwa/eddsa' if JWT.rbnacl?
24
22
 
25
23
  if JWT.rbnacl_6_or_greater?
26
24
  require_relative 'jwa/hmac_rbnacl'
@@ -29,8 +27,10 @@ elsif JWT.rbnacl?
29
27
  end
30
28
 
31
29
  module JWT
30
+ # The JWA module contains all supported algorithms.
32
31
  module JWA
33
32
  class << self
33
+ # @api private
34
34
  def resolve(algorithm)
35
35
  return find(algorithm) if algorithm.is_a?(String) || algorithm.is_a?(Symbol)
36
36
 
@@ -42,7 +42,15 @@ module JWT
42
42
  algorithm
43
43
  end
44
44
 
45
+ # @api private
46
+ def resolve_and_sort(algorithms:, preferred_algorithm:)
47
+ algs = Array(algorithms).map { |alg| JWA.resolve(alg) }
48
+ algs.partition { |alg| alg.valid_alg?(preferred_algorithm) }.flatten
49
+ end
50
+
51
+ # @deprecated The `::JWT::JWA.create` method is deprecated and will be removed in the next major version of ruby-jwt.
45
52
  def create(algorithm)
53
+ Deprecations.warning('The ::JWT::JWA.create method is deprecated and will be removed in the next major version of ruby-jwt.')
46
54
  resolve(algorithm)
47
55
  end
48
56
  end
data/lib/jwt/jwk/ec.rb CHANGED
@@ -4,6 +4,7 @@ require 'forwardable'
4
4
 
5
5
  module JWT
6
6
  module JWK
7
+ # JWK representation for Elliptic Curve (EC) keys
7
8
  class EC < KeyBase # rubocop:disable Metrics/ClassLength
8
9
  KTY = 'EC'
9
10
  KTYS = [KTY, OpenSSL::PKey::EC, JWT::JWK::EC].freeze
@@ -65,9 +66,7 @@ module JWT
65
66
  end
66
67
 
67
68
  def []=(key, value)
68
- if EC_KEY_ELEMENTS.include?(key.to_sym)
69
- raise ArgumentError, 'cannot overwrite cryptographic key attributes'
70
- end
69
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes' if EC_KEY_ELEMENTS.include?(key.to_sym)
71
70
 
72
71
  super(key, value)
73
72
  end
data/lib/jwt/jwk/hmac.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # JWK for HMAC keys
5
6
  class HMAC < KeyBase
6
7
  KTY = 'oct'
7
8
  KTYS = [KTY, String, JWT::JWK::HMAC].freeze
@@ -61,9 +62,7 @@ module JWT
61
62
  end
62
63
 
63
64
  def []=(key, value)
64
- if HMAC_KEY_ELEMENTS.include?(key.to_sym)
65
- raise ArgumentError, 'cannot overwrite cryptographic key attributes'
66
- end
65
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes' if HMAC_KEY_ELEMENTS.include?(key.to_sym)
67
66
 
68
67
  super(key, value)
69
68
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # Base for JWK implementations
5
6
  class KeyBase
6
7
  def self.inherited(klass)
7
8
  super
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # @api private
5
6
  class KeyFinder
6
7
  def initialize(options)
7
8
  @allow_nil_kid = options[:allow_nil_kid]
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # @api private
5
6
  class KidAsKeyDigest
6
7
  def initialize(jwk)
7
8
  @jwk = jwk
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # JSON Web Key (JWK) representation for Ed25519 keys
5
6
  class OKPRbNaCl < KeyBase
6
7
  KTY = 'OKP'
7
8
  KTYS = [KTY, JWT::JWK::OKPRbNaCl, RbNaCl::Signatures::Ed25519::SigningKey, RbNaCl::Signatures::Ed25519::VerifyKey].freeze
@@ -10,7 +11,7 @@ module JWT
10
11
 
11
12
  def initialize(key, params = nil, options = {})
12
13
  params ||= {}
13
-
14
+ Deprecations.warning('Using the OKP JWK for Ed25519 keys is deprecated and will be removed in a future version of ruby-jwt. Please use the ruby-eddsa gem instead.')
14
15
  # For backwards compatibility when kid was a String
15
16
  params = { kid: params } if params.is_a?(String)
16
17
 
@@ -83,9 +84,7 @@ module JWT
83
84
  x: ::JWT::Base64.url_encode(verify_key.to_bytes)
84
85
  }
85
86
 
86
- if signing_key
87
- params[:d] = ::JWT::Base64.url_encode(signing_key.to_bytes)
88
- end
87
+ params[:d] = ::JWT::Base64.url_encode(signing_key.to_bytes) if signing_key
89
88
 
90
89
  params
91
90
  end
data/lib/jwt/jwk/rsa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # JSON Web Key (JWK) representation of a RSA key
5
6
  class RSA < KeyBase # rubocop:disable Metrics/ClassLength
6
7
  BINARY = 2
7
8
  KTY = 'RSA'
@@ -64,9 +65,7 @@ module JWT
64
65
  end
65
66
 
66
67
  def []=(key, value)
67
- if RSA_KEY_ELEMENTS.include?(key.to_sym)
68
- raise ArgumentError, 'cannot overwrite cryptographic key attributes'
69
- end
68
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes' if RSA_KEY_ELEMENTS.include?(key.to_sym)
70
69
 
71
70
  super(key, value)
72
71
  end
data/lib/jwt/jwk/set.rb CHANGED
@@ -4,6 +4,8 @@ require 'forwardable'
4
4
 
5
5
  module JWT
6
6
  module JWK
7
+ # JSON Web Key Set (JWKS) representation
8
+ # https://tools.ietf.org/html/rfc7517
7
9
  class Set
8
10
  include Enumerable
9
11
  extend Forwardable
data/lib/jwt/jwk.rb CHANGED
@@ -4,6 +4,7 @@ require_relative 'jwk/key_finder'
4
4
  require_relative 'jwk/set'
5
5
 
6
6
  module JWT
7
+ # JSON Web Key (JWK)
7
8
  module JWK
8
9
  class << self
9
10
  def create_from(key, params = nil, options = {})