jwt 2.9.3 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -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 +4 -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 +6 -0
  54. data/lib/jwt/version.rb +33 -10
  55. data/lib/jwt.rb +16 -0
  56. metadata +8 -4
data/lib/jwt/token.rb ADDED
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ # Represents a JWT token
5
+ #
6
+ # Basic token signed using the HS256 algorithm:
7
+ #
8
+ # token = JWT::Token.new(payload: {pay: 'load'})
9
+ # token.sign!(algorithm: 'HS256', key: 'secret')
10
+ # token.jwt # => eyJhb....
11
+ #
12
+ # Custom headers will be combined with generated headers:
13
+ # token = JWT::Token.new(payload: {pay: 'load'}, header: {custom: "value"})
14
+ # token.sign!(algorithm: 'HS256', key: 'secret')
15
+ # token.header # => {"custom"=>"value", "alg"=>"HS256"}
16
+ #
17
+ class Token
18
+ include Claims::VerificationMethods
19
+
20
+ # Initializes a new Token instance.
21
+ #
22
+ # @param header [Hash] the header of the JWT token.
23
+ # @param payload [Hash] the payload of the JWT token.
24
+ def initialize(payload:, header: {})
25
+ @header = header&.transform_keys(&:to_s)
26
+ @payload = payload
27
+ end
28
+
29
+ # Returns the decoded signature of the JWT token.
30
+ #
31
+ # @return [String] the decoded signature of the JWT token.
32
+ def signature
33
+ @signature ||= ::JWT::Base64.url_decode(encoded_signature || '')
34
+ end
35
+
36
+ # Returns the encoded signature of the JWT token.
37
+ #
38
+ # @return [String] the encoded signature of the JWT token.
39
+ def encoded_signature
40
+ @encoded_signature ||= ::JWT::Base64.url_encode(signature)
41
+ end
42
+
43
+ # Returns the decoded header of the JWT token.
44
+ #
45
+ # @return [Hash] the header of the JWT token.
46
+ attr_reader :header
47
+
48
+ # Returns the encoded header of the JWT token.
49
+ #
50
+ # @return [String] the encoded header of the JWT token.
51
+ def encoded_header
52
+ @encoded_header ||= ::JWT::Base64.url_encode(JWT::JSON.generate(header))
53
+ end
54
+
55
+ # Returns the payload of the JWT token.
56
+ #
57
+ # @return [Hash] the payload of the JWT token.
58
+ attr_reader :payload
59
+
60
+ # Returns the encoded payload of the JWT token.
61
+ #
62
+ # @return [String] the encoded payload of the JWT token.
63
+ def encoded_payload
64
+ @encoded_payload ||= ::JWT::Base64.url_encode(JWT::JSON.generate(payload))
65
+ end
66
+
67
+ # Returns the signing input of the JWT token.
68
+ #
69
+ # @return [String] the signing input of the JWT token.
70
+ def signing_input
71
+ @signing_input ||= [encoded_header, encoded_payload].join('.')
72
+ end
73
+
74
+ # Returns the JWT token as a string.
75
+ #
76
+ # @return [String] the JWT token as a string.
77
+ # @raise [JWT::EncodeError] if the token is not signed or other encoding issues
78
+ def jwt
79
+ @jwt ||= (@signature && [encoded_header, @detached_payload ? '' : encoded_payload, encoded_signature].join('.')) || raise(::JWT::EncodeError, 'Token is not signed')
80
+ end
81
+
82
+ # Detaches the payload according to https://datatracker.ietf.org/doc/html/rfc7515#appendix-F
83
+ #
84
+ def detach_payload!
85
+ @detached_payload = true
86
+
87
+ nil
88
+ end
89
+
90
+ # Signs the JWT token.
91
+ #
92
+ # @param algorithm [String, Object] the algorithm to use for signing.
93
+ # @param key [String] the key to use for signing.
94
+ # @return [void]
95
+ # @raise [JWT::EncodeError] if the token is already signed or other problems when signing
96
+ def sign!(algorithm:, key:)
97
+ raise ::JWT::EncodeError, 'Token already signed' if @signature
98
+
99
+ JWA.resolve(algorithm).tap do |algo|
100
+ header.merge!(algo.header)
101
+ @signature = algo.sign(data: signing_input, signing_key: key)
102
+ end
103
+
104
+ nil
105
+ end
106
+
107
+ # Returns the JWT token as a string.
108
+ #
109
+ # @return [String] the JWT token as a string.
110
+ alias to_s jwt
111
+ end
112
+ end
data/lib/jwt/verify.rb CHANGED
@@ -3,10 +3,12 @@
3
3
  require_relative 'error'
4
4
 
5
5
  module JWT
6
+ # @deprecated This class is deprecated and will be removed in the next major version of ruby-jwt.
6
7
  class Verify
7
8
  DEFAULTS = { leeway: 0 }.freeze
8
9
  METHODS = %w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub verify_required_claims].freeze
9
10
 
11
+ private_constant(:DEFAULTS, :METHODS)
10
12
  class << self
11
13
  METHODS.each do |method_name|
12
14
  define_method(method_name) do |payload, options|
@@ -14,13 +16,17 @@ module JWT
14
16
  end
15
17
  end
16
18
 
19
+ # @deprecated This method is deprecated and will be removed in the next major version of ruby-jwt.
17
20
  def verify_claims(payload, options)
21
+ Deprecations.warning('The ::JWT::Verify.verify_claims method is deprecated and will be removed in the next major version of ruby-jwt')
18
22
  ::JWT::Claims.verify!(payload, options)
19
23
  true
20
24
  end
21
25
  end
22
26
 
27
+ # @deprecated This class is deprecated and will be removed in the next major version of ruby-jwt.
23
28
  def initialize(payload, options)
29
+ Deprecations.warning('The ::JWT::Verify class is deprecated and will be removed in the next major version of ruby-jwt')
24
30
  @payload = payload
25
31
  @options = DEFAULTS.merge(options)
26
32
  end
data/lib/jwt/version.rb CHANGED
@@ -1,44 +1,67 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Moments version builder module
3
+ # JSON Web Token implementation
4
+ #
5
+ # Should be up to date with the latest spec:
6
+ # https://tools.ietf.org/html/rfc7519
4
7
  module JWT
8
+ # Returns the gem version of the JWT library.
9
+ #
10
+ # @return [Gem::Version] the gem version.
5
11
  def self.gem_version
6
- Gem::Version.new VERSION::STRING
12
+ Gem::Version.new(VERSION::STRING)
7
13
  end
8
14
 
9
- # Moments version builder module
15
+ # @api private
10
16
  module VERSION
11
- # major version
12
17
  MAJOR = 2
13
- # minor version
14
- MINOR = 9
15
- # tiny version
16
- TINY = 3
17
- # alpha, beta, etc. tag
18
+ MINOR = 10
19
+ TINY = 0
18
20
  PRE = nil
19
21
 
20
- # Build version string
21
22
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
23
+
24
+ private_constant(:MAJOR, :MINOR, :TINY, :PRE)
22
25
  end
23
26
 
27
+ # Checks if the OpenSSL version is 3 or greater.
28
+ #
29
+ # @return [Boolean] true if OpenSSL version is 3 or greater, false otherwise.
30
+ # @api private
24
31
  def self.openssl_3?
25
32
  return false if OpenSSL::OPENSSL_VERSION.include?('LibreSSL')
26
33
 
27
34
  true if 3 * 0x10000000 <= OpenSSL::OPENSSL_VERSION_NUMBER
28
35
  end
29
36
 
37
+ # Checks if the RbNaCl library is defined.
38
+ #
39
+ # @return [Boolean] true if RbNaCl is defined, false otherwise.
40
+ # @api private
30
41
  def self.rbnacl?
31
42
  defined?(::RbNaCl)
32
43
  end
33
44
 
45
+ # Checks if the RbNaCl library version is 6.0.0 or greater.
46
+ #
47
+ # @return [Boolean] true if RbNaCl version is 6.0.0 or greater, false otherwise.
48
+ # @api private
34
49
  def self.rbnacl_6_or_greater?
35
50
  rbnacl? && ::Gem::Version.new(::RbNaCl::VERSION) >= ::Gem::Version.new('6.0.0')
36
51
  end
37
52
 
53
+ # Checks if there is an OpenSSL 3 HMAC empty key regression.
54
+ #
55
+ # @return [Boolean] true if there is an OpenSSL 3 HMAC empty key regression, false otherwise.
56
+ # @api private
38
57
  def self.openssl_3_hmac_empty_key_regression?
39
58
  openssl_3? && openssl_version <= ::Gem::Version.new('3.0.0')
40
59
  end
41
60
 
61
+ # Returns the OpenSSL version.
62
+ #
63
+ # @return [Gem::Version] the OpenSSL version.
64
+ # @api private
42
65
  def self.openssl_version
43
66
  @openssl_version ||= ::Gem::Version.new(OpenSSL::VERSION)
44
67
  end
data/lib/jwt.rb CHANGED
@@ -10,6 +10,8 @@ require 'jwt/encode'
10
10
  require 'jwt/error'
11
11
  require 'jwt/jwk'
12
12
  require 'jwt/claims'
13
+ require 'jwt/encoded_token'
14
+ require 'jwt/token'
13
15
 
14
16
  require 'jwt/claims_validator'
15
17
  require 'jwt/verify'
@@ -23,6 +25,13 @@ module JWT
23
25
 
24
26
  module_function
25
27
 
28
+ # Encodes a payload into a JWT.
29
+ #
30
+ # @param payload [Hash] the payload to encode.
31
+ # @param key [String] the key used to sign the JWT.
32
+ # @param algorithm [String] the algorithm used to sign the JWT.
33
+ # @param header_fields [Hash] additional headers to include in the JWT.
34
+ # @return [String] the encoded JWT.
26
35
  def encode(payload, key, algorithm = 'HS256', header_fields = {})
27
36
  Encode.new(payload: payload,
28
37
  key: key,
@@ -30,6 +39,13 @@ module JWT
30
39
  headers: header_fields).segments
31
40
  end
32
41
 
42
+ # Decodes a JWT to extract the payload and header
43
+ #
44
+ # @param jwt [String] the JWT to decode.
45
+ # @param key [String] the key used to verify the JWT.
46
+ # @param verify [Boolean] whether to verify the JWT signature.
47
+ # @param options [Hash] additional options for decoding.
48
+ # @return [Array<Hash>] the decoded payload and headers.
33
49
  def decode(jwt, key = nil, verify = true, options = {}, &keyfinder) # rubocop:disable Style/OptionalBooleanParameter
34
50
  Deprecations.context do
35
51
  Decode.new(jwt, key, verify, configuration.decode.to_h.merge(options), &keyfinder).decode_segments
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.3
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Rudat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-03 00:00:00.000000000 Z
11
+ date: 2024-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -125,6 +125,7 @@ files:
125
125
  - lib/jwt/base64.rb
126
126
  - lib/jwt/claims.rb
127
127
  - lib/jwt/claims/audience.rb
128
+ - lib/jwt/claims/crit.rb
128
129
  - lib/jwt/claims/decode_verifier.rb
129
130
  - lib/jwt/claims/expiration.rb
130
131
  - lib/jwt/claims/issued_at.rb
@@ -134,6 +135,7 @@ files:
134
135
  - lib/jwt/claims/numeric.rb
135
136
  - lib/jwt/claims/required.rb
136
137
  - lib/jwt/claims/subject.rb
138
+ - lib/jwt/claims/verification_methods.rb
137
139
  - lib/jwt/claims/verifier.rb
138
140
  - lib/jwt/claims_validator.rb
139
141
  - lib/jwt/configuration.rb
@@ -143,6 +145,7 @@ files:
143
145
  - lib/jwt/decode.rb
144
146
  - lib/jwt/deprecations.rb
145
147
  - lib/jwt/encode.rb
148
+ - lib/jwt/encoded_token.rb
146
149
  - lib/jwt/error.rb
147
150
  - lib/jwt/json.rb
148
151
  - lib/jwt/jwa.rb
@@ -168,6 +171,7 @@ files:
168
171
  - lib/jwt/jwk/rsa.rb
169
172
  - lib/jwt/jwk/set.rb
170
173
  - lib/jwt/jwk/thumbprint.rb
174
+ - lib/jwt/token.rb
171
175
  - lib/jwt/verify.rb
172
176
  - lib/jwt/version.rb
173
177
  - lib/jwt/x5c_key_finder.rb
@@ -177,7 +181,7 @@ licenses:
177
181
  - MIT
178
182
  metadata:
179
183
  bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
180
- changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.9.3/CHANGELOG.md
184
+ changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.10.0/CHANGELOG.md
181
185
  rubygems_mfa_required: 'true'
182
186
  post_install_message:
183
187
  rdoc_options: []
@@ -194,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
198
  - !ruby/object:Gem::Version
195
199
  version: '0'
196
200
  requirements: []
197
- rubygems_version: 3.5.16
201
+ rubygems_version: 3.5.22
198
202
  signing_key:
199
203
  specification_version: 4
200
204
  summary: JSON Web Token implementation in Ruby