jwt 2.8.0 → 2.8.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +17 -0
- data/lib/jwt/base64.rb +4 -2
- data/lib/jwt/configuration/container.rb +14 -3
- data/lib/jwt/configuration/jwk_configuration.rb +1 -1
- data/lib/jwt/decode.rb +10 -10
- data/lib/jwt/deprecations.rb +48 -0
- data/lib/jwt/error.rb +1 -0
- data/lib/jwt/jwa/hmac_rbnacl.rb +2 -2
- data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +2 -2
- data/lib/jwt/jwk/ec.rb +20 -20
- data/lib/jwt/jwk/key_finder.rb +4 -4
- data/lib/jwt/jwk/set.rb +1 -1
- data/lib/jwt/verify.rb +9 -9
- data/lib/jwt/version.rb +1 -1
- data/lib/jwt/x5c_key_finder.rb +2 -2
- data/lib/jwt.rb +4 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fc1b13d678680a3d1b23e06cad091deb0f3ffff77783a99cd1d1f7231938563
|
4
|
+
data.tar.gz: f7d3f5294cb3b6ba57c2772a58c50ee2d55cf6412db6b707a38c74b381662777
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f4602ed313d982db0a2e469c2fc3b58aa0de226f85e332501628d9f7b59ed8a84e78691b57f14ddf153c4be028e9b3caa13d9b3231996c798e9e63f69f4d10a
|
7
|
+
data.tar.gz: a3ed20caccfe2c2979426b41a6e0bbeeabe67157643c4571836642f48ccf76ba8f58bb3270501eeefcbd53e1d027de1b558310a083360ca644157934ce3c06bf
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v2.8.2](https://github.com/jwt/ruby-jwt/tree/v2.8.2) (2024-06-18)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.8.1...v2.8.2)
|
6
|
+
|
7
|
+
**Fixes and enhancements:**
|
8
|
+
|
9
|
+
- Print deprecation warnings only on when token decoding succeeds [#600](https://github.com/jwt/ruby-jwt/pull/600) ([@anakinj](https://github.com/anakinj))
|
10
|
+
- Unify code style [#602](https://github.com/jwt/ruby-jwt/pull/602) ([@anakinj](https://github.com/anakinj))
|
11
|
+
|
12
|
+
## [v2.8.1](https://github.com/jwt/ruby-jwt/tree/v2.8.1) (2024-02-29)
|
13
|
+
|
14
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.8.0...v2.8.1)
|
15
|
+
|
16
|
+
**Features:**
|
17
|
+
|
18
|
+
- Configurable base64 decode behaviour [#589](https://github.com/jwt/ruby-jwt/pull/589) ([@anakinj](https://github.com/anakinj))
|
19
|
+
|
20
|
+
**Fixes and enhancements:**
|
21
|
+
|
22
|
+
- Output deprecation warnings once [#589](https://github.com/jwt/ruby-jwt/pull/589) ([@anakinj](https://github.com/anakinj))
|
23
|
+
|
3
24
|
## [v2.8.0](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2024-02-17)
|
4
25
|
|
5
26
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.1...v2.8.0)
|
data/README.md
CHANGED
@@ -43,6 +43,23 @@ The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cr
|
|
43
43
|
|
44
44
|
See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)
|
45
45
|
|
46
|
+
### Deprecation warnings
|
47
|
+
|
48
|
+
Deprecation warnings are logged once (`:once` option) by default to avoid spam in logs. Other options are `:silent` to completely silence warnings and `:warn` to log every time a deprecated path is executed.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
JWT.configuration.deprecation_warnings = :warn # default is :once
|
52
|
+
```
|
53
|
+
|
54
|
+
### Base64 decoding
|
55
|
+
|
56
|
+
In the past the gem has been supporting the Base64 decoding specified in [RFC2045](https://www.rfc-editor.org/rfc/rfc2045) allowing newlines and blanks in the base64 encoded payload. In future versions base64 decoding will be stricter and only comply to [RFC4648](https://www.rfc-editor.org/rfc/rfc4648).
|
57
|
+
|
58
|
+
The stricter base64 decoding when processing tokens can be done via the `strict_base64_decoding` configuration accessor.
|
59
|
+
```ruby
|
60
|
+
JWT.configuration.strict_base64_decoding = true # default is false
|
61
|
+
```
|
62
|
+
|
46
63
|
### **NONE**
|
47
64
|
|
48
65
|
* none - unsigned token
|
data/lib/jwt/base64.rb
CHANGED
@@ -17,9 +17,11 @@ module JWT
|
|
17
17
|
::Base64.urlsafe_decode64(str)
|
18
18
|
rescue ArgumentError => e
|
19
19
|
raise unless e.message == 'invalid base64'
|
20
|
+
raise Base64DecodeError, 'Invalid base64 encoding' if JWT.configuration.strict_base64_decoding
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
loose_urlsafe_decode64(str).tap do
|
23
|
+
Deprecations.warning('Invalid base64 input detected, could be because of invalid padding, trailing whitespaces or newline chars. Graceful handling of invalid input will be dropped in the next major version of ruby-jwt', only_if_valid: true)
|
24
|
+
end
|
23
25
|
end
|
24
26
|
|
25
27
|
def loose_urlsafe_decode64(str)
|
@@ -6,15 +6,26 @@ require_relative 'jwk_configuration'
|
|
6
6
|
module JWT
|
7
7
|
module Configuration
|
8
8
|
class Container
|
9
|
-
attr_accessor :decode, :jwk
|
9
|
+
attr_accessor :decode, :jwk, :strict_base64_decoding
|
10
|
+
attr_reader :deprecation_warnings
|
10
11
|
|
11
12
|
def initialize
|
12
13
|
reset!
|
13
14
|
end
|
14
15
|
|
15
16
|
def reset!
|
16
|
-
@decode
|
17
|
-
@jwk
|
17
|
+
@decode = DecodeConfiguration.new
|
18
|
+
@jwk = JwkConfiguration.new
|
19
|
+
@strict_base64_decoding = false
|
20
|
+
|
21
|
+
self.deprecation_warnings = :once
|
22
|
+
end
|
23
|
+
|
24
|
+
DEPRECATION_WARNINGS_VALUES = %i[once warn silent].freeze
|
25
|
+
def deprecation_warnings=(value)
|
26
|
+
raise ArgumentError, "Invalid deprecation_warnings value #{value}. Supported values: #{DEPRECATION_WARNINGS_VALUES}" unless DEPRECATION_WARNINGS_VALUES.include?(value)
|
27
|
+
|
28
|
+
@deprecation_warnings = value
|
18
29
|
end
|
19
30
|
end
|
20
31
|
end
|
data/lib/jwt/decode.rb
CHANGED
@@ -10,7 +10,7 @@ module JWT
|
|
10
10
|
# Decoding logic for JWT
|
11
11
|
class Decode
|
12
12
|
def initialize(jwt, key, verify, options, &keyfinder)
|
13
|
-
raise
|
13
|
+
raise JWT::DecodeError, 'Nil JSON web token' unless jwt
|
14
14
|
|
15
15
|
@jwt = jwt
|
16
16
|
@key = key
|
@@ -30,7 +30,7 @@ module JWT
|
|
30
30
|
verify_signature
|
31
31
|
verify_claims
|
32
32
|
end
|
33
|
-
raise
|
33
|
+
raise JWT::DecodeError, 'Not enough or too many segments' unless header && payload
|
34
34
|
|
35
35
|
[payload, header]
|
36
36
|
end
|
@@ -46,21 +46,21 @@ module JWT
|
|
46
46
|
|
47
47
|
return if Array(@key).any? { |key| verify_signature_for?(key) }
|
48
48
|
|
49
|
-
raise
|
49
|
+
raise JWT::VerificationError, 'Signature verification failed'
|
50
50
|
end
|
51
51
|
|
52
52
|
def verify_algo
|
53
|
-
raise
|
54
|
-
raise
|
55
|
-
raise
|
53
|
+
raise JWT::IncorrectAlgorithm, 'An algorithm must be specified' if allowed_algorithms.empty?
|
54
|
+
raise JWT::IncorrectAlgorithm, 'Token is missing alg header' unless alg_in_header
|
55
|
+
raise JWT::IncorrectAlgorithm, 'Expected a different algorithm' if allowed_and_valid_algorithms.empty?
|
56
56
|
end
|
57
57
|
|
58
58
|
def set_key
|
59
59
|
@key = find_key(&@keyfinder) if @keyfinder
|
60
60
|
@key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks], allow_nil_kid: @options[:allow_nil_kid]).key_for(header['kid']) if @options[:jwks]
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
return unless (x5c_options = @options[:x5c])
|
62
|
+
|
63
|
+
@key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(header['x5c'])
|
64
64
|
end
|
65
65
|
|
66
66
|
def verify_signature_for?(key)
|
@@ -122,7 +122,7 @@ module JWT
|
|
122
122
|
return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed
|
123
123
|
return if segment_length == 2 && none_algorithm?
|
124
124
|
|
125
|
-
raise
|
125
|
+
raise JWT::DecodeError, 'Not enough or too many segments'
|
126
126
|
end
|
127
127
|
|
128
128
|
def segment_length
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
# Deprecations module to handle deprecation warnings in the gem
|
5
|
+
module Deprecations
|
6
|
+
class << self
|
7
|
+
def context
|
8
|
+
yield.tap { emit_warnings }
|
9
|
+
ensure
|
10
|
+
Thread.current[:jwt_warning_store] = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def warning(message, only_if_valid: false)
|
14
|
+
method_name = only_if_valid ? :store : :warn
|
15
|
+
case JWT.configuration.deprecation_warnings
|
16
|
+
when :once
|
17
|
+
return if record_warned(message)
|
18
|
+
when :warn
|
19
|
+
# noop
|
20
|
+
else
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
send(method_name, "[DEPRECATION WARNING] #{message}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def store(message)
|
28
|
+
(Thread.current[:jwt_warning_store] ||= []) << message
|
29
|
+
end
|
30
|
+
|
31
|
+
def emit_warnings
|
32
|
+
return if Thread.current[:jwt_warning_store].nil?
|
33
|
+
|
34
|
+
Thread.current[:jwt_warning_store].each { |warning| warn(warning) }
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def record_warned(message)
|
40
|
+
@warned ||= []
|
41
|
+
return true if @warned.include?(message)
|
42
|
+
|
43
|
+
@warned << message
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/jwt/error.rb
CHANGED
data/lib/jwt/jwa/hmac_rbnacl.rb
CHANGED
@@ -7,7 +7,7 @@ module JWT
|
|
7
7
|
SUPPORTED = MAPPING.keys
|
8
8
|
class << self
|
9
9
|
def sign(algorithm, msg, key)
|
10
|
-
|
10
|
+
Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
11
11
|
if (hmac = resolve_algorithm(algorithm))
|
12
12
|
hmac.auth(key_for_rbnacl(hmac, key).encode('binary'), msg.encode('binary'))
|
13
13
|
else
|
@@ -16,7 +16,7 @@ module JWT
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def verify(algorithm, key, signing_input, signature)
|
19
|
-
|
19
|
+
Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
20
20
|
if (hmac = resolve_algorithm(algorithm))
|
21
21
|
hmac.verify(key_for_rbnacl(hmac, key).encode('binary'), signature.encode('binary'), signing_input.encode('binary'))
|
22
22
|
else
|
@@ -9,7 +9,7 @@ module JWT
|
|
9
9
|
class << self
|
10
10
|
def sign(algorithm, msg, key)
|
11
11
|
key ||= ''
|
12
|
-
|
12
|
+
Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
13
13
|
raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
|
14
14
|
|
15
15
|
if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
|
@@ -21,7 +21,7 @@ module JWT
|
|
21
21
|
|
22
22
|
def verify(algorithm, key, signing_input, signature)
|
23
23
|
key ||= ''
|
24
|
-
|
24
|
+
Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
25
25
|
raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
|
26
26
|
|
27
27
|
if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
|
data/lib/jwt/jwk/ec.rb
CHANGED
@@ -153,26 +153,26 @@ module JWT
|
|
153
153
|
)
|
154
154
|
|
155
155
|
sequence = if jwk_d
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
156
|
+
# https://datatracker.ietf.org/doc/html/rfc5915.html
|
157
|
+
# ECPrivateKey ::= SEQUENCE {
|
158
|
+
# version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
|
159
|
+
# privateKey OCTET STRING,
|
160
|
+
# parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
|
161
|
+
# publicKey [1] BIT STRING OPTIONAL
|
162
|
+
# }
|
163
|
+
|
164
|
+
OpenSSL::ASN1::Sequence([
|
165
|
+
OpenSSL::ASN1::Integer(1),
|
166
|
+
OpenSSL::ASN1::OctetString(OpenSSL::BN.new(decode_octets(jwk_d), 2).to_s(2)),
|
167
|
+
OpenSSL::ASN1::ObjectId(curve, 0, :EXPLICIT),
|
168
|
+
OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT)
|
169
|
+
])
|
170
|
+
else
|
171
|
+
OpenSSL::ASN1::Sequence([
|
172
|
+
OpenSSL::ASN1::Sequence([OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(curve)]),
|
173
|
+
OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
|
174
|
+
])
|
175
|
+
end
|
176
176
|
|
177
177
|
OpenSSL::PKey::EC.new(sequence.to_der)
|
178
178
|
end
|
data/lib/jwt/jwk/key_finder.rb
CHANGED
@@ -8,10 +8,10 @@ module JWT
|
|
8
8
|
jwks_or_loader = options[:jwks]
|
9
9
|
|
10
10
|
@jwks_loader = if jwks_or_loader.respond_to?(:call)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
jwks_or_loader
|
12
|
+
else
|
13
|
+
->(_options) { jwks_or_loader }
|
14
|
+
end
|
15
15
|
end
|
16
16
|
|
17
17
|
def key_for(kid)
|
data/lib/jwt/jwk/set.rb
CHANGED
data/lib/jwt/verify.rb
CHANGED
@@ -34,19 +34,19 @@ module JWT
|
|
34
34
|
return unless (options_aud = @options[:aud])
|
35
35
|
|
36
36
|
aud = @payload['aud']
|
37
|
-
raise
|
37
|
+
raise JWT::InvalidAudError, "Invalid audience. Expected #{options_aud}, received #{aud || '<none>'}" if ([*aud] & [*options_aud]).empty?
|
38
38
|
end
|
39
39
|
|
40
40
|
def verify_expiration
|
41
41
|
return unless contains_key?(@payload, 'exp')
|
42
|
-
raise
|
42
|
+
raise JWT::ExpiredSignature, 'Signature has expired' if @payload['exp'].to_i <= (Time.now.to_i - exp_leeway)
|
43
43
|
end
|
44
44
|
|
45
45
|
def verify_iat
|
46
46
|
return unless contains_key?(@payload, 'iat')
|
47
47
|
|
48
48
|
iat = @payload['iat']
|
49
|
-
raise
|
49
|
+
raise JWT::InvalidIatError, 'Invalid iat' if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f
|
50
50
|
end
|
51
51
|
|
52
52
|
def verify_iss
|
@@ -60,7 +60,7 @@ module JWT
|
|
60
60
|
when *options_iss
|
61
61
|
nil
|
62
62
|
else
|
63
|
-
raise
|
63
|
+
raise JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || '<none>'}"
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
@@ -70,29 +70,29 @@ module JWT
|
|
70
70
|
|
71
71
|
if options_verify_jti.respond_to?(:call)
|
72
72
|
verified = options_verify_jti.arity == 2 ? options_verify_jti.call(jti, @payload) : options_verify_jti.call(jti)
|
73
|
-
raise
|
73
|
+
raise JWT::InvalidJtiError, 'Invalid jti' unless verified
|
74
74
|
elsif jti.to_s.strip.empty?
|
75
|
-
raise
|
75
|
+
raise JWT::InvalidJtiError, 'Missing jti'
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
79
|
def verify_not_before
|
80
80
|
return unless contains_key?(@payload, 'nbf')
|
81
|
-
raise
|
81
|
+
raise JWT::ImmatureSignature, 'Signature nbf has not been reached' if @payload['nbf'].to_i > (Time.now.to_i + nbf_leeway)
|
82
82
|
end
|
83
83
|
|
84
84
|
def verify_sub
|
85
85
|
return unless (options_sub = @options[:sub])
|
86
86
|
|
87
87
|
sub = @payload['sub']
|
88
|
-
raise
|
88
|
+
raise JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || '<none>'}" unless sub.to_s == options_sub.to_s
|
89
89
|
end
|
90
90
|
|
91
91
|
def verify_required_claims
|
92
92
|
return unless (options_required_claims = @options[:required_claims])
|
93
93
|
|
94
94
|
options_required_claims.each do |required_claim|
|
95
|
-
raise
|
95
|
+
raise JWT::MissingRequiredClaim, "Missing required claim #{required_claim}" unless contains_key?(@payload, required_claim)
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
data/lib/jwt/version.rb
CHANGED
data/lib/jwt/x5c_key_finder.rb
CHANGED
@@ -7,7 +7,7 @@ module JWT
|
|
7
7
|
# See https://tools.ietf.org/html/rfc7515#section-4.1.6
|
8
8
|
class X5cKeyFinder
|
9
9
|
def initialize(root_certificates, crls = nil)
|
10
|
-
raise
|
10
|
+
raise ArgumentError, 'Root certificates must be specified' unless root_certificates
|
11
11
|
|
12
12
|
@store = build_store(root_certificates, crls)
|
13
13
|
end
|
@@ -24,7 +24,7 @@ module JWT
|
|
24
24
|
error = "#{error} Certificate subject: #{current_cert.subject}."
|
25
25
|
end
|
26
26
|
|
27
|
-
raise
|
27
|
+
raise JWT::VerificationError, error
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
data/lib/jwt.rb
CHANGED
@@ -5,6 +5,7 @@ require 'jwt/base64'
|
|
5
5
|
require 'jwt/json'
|
6
6
|
require 'jwt/decode'
|
7
7
|
require 'jwt/configuration'
|
8
|
+
require 'jwt/deprecations'
|
8
9
|
require 'jwt/encode'
|
9
10
|
require 'jwt/error'
|
10
11
|
require 'jwt/jwk'
|
@@ -26,6 +27,8 @@ module JWT
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def decode(jwt, key = nil, verify = true, options = {}, &keyfinder) # rubocop:disable Style/OptionalBooleanParameter
|
29
|
-
|
30
|
+
Deprecations.context do
|
31
|
+
Decode.new(jwt, key, verify, configuration.decode.to_h.merge(options), &keyfinder).decode_segments
|
32
|
+
end
|
30
33
|
end
|
31
34
|
end
|
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.8.
|
4
|
+
version: 2.8.2
|
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-
|
11
|
+
date: 2024-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|
@@ -129,6 +129,7 @@ files:
|
|
129
129
|
- lib/jwt/configuration/decode_configuration.rb
|
130
130
|
- lib/jwt/configuration/jwk_configuration.rb
|
131
131
|
- lib/jwt/decode.rb
|
132
|
+
- lib/jwt/deprecations.rb
|
132
133
|
- lib/jwt/encode.rb
|
133
134
|
- lib/jwt/error.rb
|
134
135
|
- lib/jwt/json.rb
|
@@ -162,7 +163,7 @@ licenses:
|
|
162
163
|
- MIT
|
163
164
|
metadata:
|
164
165
|
bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
|
165
|
-
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.8.
|
166
|
+
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.8.2/CHANGELOG.md
|
166
167
|
rubygems_mfa_required: 'true'
|
167
168
|
post_install_message:
|
168
169
|
rdoc_options: []
|
@@ -179,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
179
180
|
- !ruby/object:Gem::Version
|
180
181
|
version: '0'
|
181
182
|
requirements: []
|
182
|
-
rubygems_version: 3.3
|
183
|
+
rubygems_version: 3.5.3
|
183
184
|
signing_key:
|
184
185
|
specification_version: 4
|
185
186
|
summary: JSON Web Token implementation in Ruby
|