jwt 3.2.0 → 3.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +12 -4
- data/UPGRADING.md +54 -0
- data/lib/jwt/claims/decode_verifier.rb +1 -1
- data/lib/jwt/claims/issued_at.rb +12 -1
- data/lib/jwt/claims/verifier.rb +5 -3
- data/lib/jwt/claims.rb +1 -1
- data/lib/jwt/configuration/decode_configuration.rb +1 -1
- data/lib/jwt/decode.rb +6 -6
- data/lib/jwt/encoded_token.rb +22 -14
- data/lib/jwt/error.rb +50 -23
- data/lib/jwt/jwa/ecdsa.rb +9 -4
- data/lib/jwt/jwa/hmac.rb +10 -15
- data/lib/jwt/jwa/ps.rb +3 -0
- data/lib/jwt/jwa/rsa.rb +3 -0
- data/lib/jwt/jwa/signing_algorithm.rb +1 -1
- data/lib/jwt/jwa/unsupported.rb +1 -1
- data/lib/jwt/jwa.rb +2 -2
- data/lib/jwt/jwk/ec.rb +1 -1
- data/lib/jwt/jwk/hmac.rb +1 -1
- data/lib/jwt/jwk/key_finder.rb +4 -4
- data/lib/jwt/jwk/rsa.rb +1 -1
- data/lib/jwt/jwk/set.rb +28 -14
- data/lib/jwt/jwk.rb +1 -1
- data/lib/jwt/token.rb +2 -1
- data/lib/jwt/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9b0bbac64c8b97deb791cc74f29243c6c04cbc2c3a63904484259c5379a2650f
|
|
4
|
+
data.tar.gz: 0252d7993ad937c9cb961d4f2ff4ce9cef9fc7b503fadb2ba4e85923752ed6b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cdef3e40a9879182bd028df5dad15676280ba567839a12d3ca31f9569c9b1d44b02f959b256e1d95d1c9d3e882a3ab6d944dbcce0f22d31a0658cd5589e14917
|
|
7
|
+
data.tar.gz: 88f3879e2061b072b15c1a001ff7c62e674fcf61a2edd610b19f95b9aac9dfd7fd07ce2aa416a3859bcc1afb3e59f18cf12e95898027102bd16f13103d04aa26
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v3.3.0](https://github.com/jwt/ruby-jwt/tree/v3.3.0) (2026-09-11)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v3.2.0...v3.3.0)
|
|
6
|
+
|
|
7
|
+
**Features:**
|
|
8
|
+
|
|
9
|
+
- Allow a leeway to be given for the `iat` claim verification [#747](https://github.com/jwt/ruby-jwt/pull/747) - ([@denis1011101](https://github.com/denis1011101))
|
|
10
|
+
- Revamp the error hierarchy under a new `JWT::Error` base class; signing failures now consistently raise `JWT::EncodeError`, see [UPGRADING.md](UPGRADING.md) [#722](https://github.com/jwt/ruby-jwt/pull/722) ([@anakinj](https://github.com/anakinj))
|
|
11
|
+
|
|
12
|
+
**Fixes and enhancements:**
|
|
13
|
+
|
|
14
|
+
- Refactor `JWT::JWK::Set#initialize` so each construction path is a named method [#758](https://github.com/jwt/ruby-jwt/pull/758) ([@anakinj](https://github.com/anakinj))
|
|
15
|
+
- Fix rejection of unknown algorithms from JWKs for RFC compliance and pquip [#728](https://github.com/jwt/ruby-jwt/pull/728)
|
|
16
|
+
- Fix the `Style/DirectiveScope` RuboCop offense failing the build [#752](https://github.com/jwt/ruby-jwt/pull/752)
|
|
17
|
+
- Fix `JWT::JWK::Set` sharing its key collection with the set it was copied from [#751](https://github.com/jwt/ruby-jwt/pull/751)
|
|
18
|
+
- Reset the decoded payload and verification state in `JWT::EncodedToken#encoded_payload=` [#749](https://github.com/jwt/ruby-jwt/issues/749)
|
|
19
|
+
- Fix `JWT::Token#detach_payload!` not invalidating an already rendered token [#748](https://github.com/jwt/ruby-jwt/issues/748)
|
|
20
|
+
|
|
3
21
|
## [v3.2.0](https://github.com/jwt/ruby-jwt/tree/v3.2.0) (2026-05-13)
|
|
4
22
|
|
|
5
23
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v3.1.2...v3.2.0)
|
data/README.md
CHANGED
|
@@ -532,7 +532,9 @@ end
|
|
|
532
532
|
|
|
533
533
|
From [Oauth JSON Web Token 4.1.6. "iat" (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6):
|
|
534
534
|
|
|
535
|
-
> The `iat` (issued at) claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT.
|
|
535
|
+
> The `iat` (issued at) claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT. Its value MUST be a number containing a **_NumericDate_** value. Use of this claim is OPTIONAL.
|
|
536
|
+
|
|
537
|
+
The global `leeway` option does not apply to `iat`. To allow for clock drift, pass `leeway` under `verify_iat`, as shown below. The `iat_leeway` option was removed in version 2.2.0.
|
|
536
538
|
|
|
537
539
|
```ruby
|
|
538
540
|
iat = Time.now.to_i
|
|
@@ -548,6 +550,12 @@ rescue JWT::InvalidIatError
|
|
|
548
550
|
end
|
|
549
551
|
```
|
|
550
552
|
|
|
553
|
+
By default, `iat` verification allows no clock drift. To allow drift between the issuer and verifier clocks, pass a leeway value explicitly:
|
|
554
|
+
|
|
555
|
+
```ruby
|
|
556
|
+
decoded_token = JWT.decode(token, hmac_secret, true, { verify_iat: { leeway: 30 }, algorithm: 'HS256' })
|
|
557
|
+
```
|
|
558
|
+
|
|
551
559
|
### Subject Claim
|
|
552
560
|
|
|
553
561
|
From [Oauth JSON Web Token 4.1.2. "sub" (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2):
|
|
@@ -632,7 +640,7 @@ end
|
|
|
632
640
|
|
|
633
641
|
begin
|
|
634
642
|
JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls } })
|
|
635
|
-
rescue JWT::
|
|
643
|
+
rescue JWT::TokenError
|
|
636
644
|
# Handle error, e.g. x5c header certificate revoked or expired
|
|
637
645
|
end
|
|
638
646
|
```
|
|
@@ -697,8 +705,8 @@ begin
|
|
|
697
705
|
JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwks_loader })
|
|
698
706
|
rescue JWT::JWKError
|
|
699
707
|
# Handle problems with the provided JWKs
|
|
700
|
-
rescue JWT::
|
|
701
|
-
# Handle other
|
|
708
|
+
rescue JWT::TokenError
|
|
709
|
+
# Handle other token related issues e.g. no kid in header, no matching public key found etc.
|
|
702
710
|
end
|
|
703
711
|
```
|
|
704
712
|
|
data/UPGRADING.md
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
# Upgrading ruby-jwt to >= 3.3.0
|
|
2
|
+
|
|
3
|
+
## Error hierarchy revamp
|
|
4
|
+
|
|
5
|
+
The [error classes were reorganised](https://github.com/jwt/ruby-jwt/pull/722) under a new `JWT::Error` base class, so failures can be rescued by category instead of one class at a time:
|
|
6
|
+
|
|
7
|
+
- `JWT::Error` is the base class for everything the gem raises.
|
|
8
|
+
- `JWT::TokenError` covers every failure in processing a token, and splits into `JWT::MalformedTokenError` (the token is structurally invalid), `JWT::SignatureError` (signature and algorithm problems) and `JWT::ClaimValidationError` (a claim did not verify).
|
|
9
|
+
- `JWT::VerificationKeyError`, a subclass of `JWT::VerificationError`, says the key or algorithm given for verification cannot be used, as opposed to a signature that does not match.
|
|
10
|
+
|
|
11
|
+
### Backwards compatibility
|
|
12
|
+
|
|
13
|
+
This is a backwards compatible change for effectively every application. The new classes were inserted above the existing ones rather than replacing them, so every error class you already rescue keeps its name, its meaning and everything it used to catch. In the ordinary case, upgrading needs no code change at all.
|
|
14
|
+
|
|
15
|
+
There is one exception, and it is narrow enough to be worth stating precisely. It applies only if all three of the following are true:
|
|
16
|
+
|
|
17
|
+
1. You rescue around `JWT.encode`, not around `JWT.decode`.
|
|
18
|
+
2. The class you rescue is `JWT::DecodeError`, `JWT::IncorrectAlgorithm`, `JWT::UnsupportedEcdsaCurve` or `ArgumentError`.
|
|
19
|
+
3. That rescue is reached at all, which takes a key or algorithm that cannot sign in the first place.
|
|
20
|
+
|
|
21
|
+
If any one of the three does not hold, there is nothing to do. If all three do, the fix is a one line change, described in the next section.
|
|
22
|
+
|
|
23
|
+
Why that is a small target in practice:
|
|
24
|
+
|
|
25
|
+
- **Decoding is untouched.** `JWT::DecodeError` is deprecated in favour of the classes above, but it keeps its meaning: every error class except `JWT::EncodeError` still inherits from it. A `rescue JWT::DecodeError` around `JWT.decode` catches everything it caught before, and the specific classes it has always raised, such as `JWT::ExpiredSignature`, are unchanged.
|
|
26
|
+
- **Signing that currently works is untouched.** Every case in the table below is an unusable key or algorithm, a misconfiguration that fails on every call made with that key. None of them can be triggered by a particular payload or token, so an application that signs tokens successfully today does not reach them at all.
|
|
27
|
+
- **Failures you let escape are untouched.** All of these raised before and still raise; only the class changed. Code that does not rescue them behaves exactly as it did.
|
|
28
|
+
|
|
29
|
+
One decode-side behaviour did change, but in the direction of catching more: `RS*` and `PS*` now reject a key of the wrong type with a `JWT::VerificationKeyError`, which is a `JWT::DecodeError`, instead of letting a `NoMethodError` escape.
|
|
30
|
+
|
|
31
|
+
### Signing failures now raise `JWT::EncodeError`
|
|
32
|
+
|
|
33
|
+
Signing failures used to surface as decode errors, and are now consistently `JWT::EncodeError`, which is deliberately not a `JWT::DecodeError`:
|
|
34
|
+
|
|
35
|
+
| Signing with | Used to raise | Now raises |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| a `nil`, empty or too short HMAC key | `JWT::DecodeError` | `JWT::EncodeError` |
|
|
38
|
+
| an ECDSA key whose curve does not match the algorithm | `JWT::IncorrectAlgorithm` | `JWT::EncodeError` |
|
|
39
|
+
| an ECDSA key on an unsupported curve | `JWT::UnsupportedEcdsaCurve` | `JWT::EncodeError` |
|
|
40
|
+
| a JWK whose `alg` does not match the algorithm | `JWT::DecodeError` | `JWT::EncodeError` |
|
|
41
|
+
| an `RS*` or `PS*` public key | `ArgumentError` | `JWT::EncodeError` |
|
|
42
|
+
|
|
43
|
+
If you wrap `JWT.encode` in `rescue JWT::DecodeError`, `rescue JWT::IncorrectAlgorithm` or `rescue JWT::UnsupportedEcdsaCurve`, rescue `JWT::EncodeError` or `JWT::Error` instead.
|
|
44
|
+
|
|
45
|
+
### Why this is a minor release
|
|
46
|
+
|
|
47
|
+
The exception described above is a real incompatibility, and 3.3.0 is still deliberately a minor release rather than a new major.
|
|
48
|
+
|
|
49
|
+
The reason is that nothing here turns a call that used to succeed into one that fails, or the other way round. Every case in the table raised an error before and raises an error now, only under a different class. No token is signed that would previously have been refused, no token verifies that would previously have been rejected, and no signature is produced or accepted on different terms than before. What changed is which `rescue` clause matches on a path that was already failing.
|
|
50
|
+
|
|
51
|
+
Weighed against the cost of a second major migration so soon after 3.0.0, that did not seem to warrant one.
|
|
52
|
+
|
|
53
|
+
If you find a case where this change affects whether a call succeeds, rather than which error it raises when it fails, please [open an issue](https://github.com/jwt/ruby-jwt/issues). That would be a bug rather than an intended consequence of the reorganisation.
|
|
54
|
+
|
|
1
55
|
# Upgrading ruby-jwt to >= 3.0.0
|
|
2
56
|
|
|
3
57
|
## Removal of the indirect [RbNaCl](https://github.com/RubyCrypto/rbnacl) dependency
|
|
@@ -15,7 +15,7 @@ module JWT
|
|
|
15
15
|
verify_expiration: ->(options) { Claims::Expiration.new(leeway: options[:exp_leeway] || options[:leeway]) },
|
|
16
16
|
verify_not_before: ->(options) { Claims::NotBefore.new(leeway: options[:nbf_leeway] || options[:leeway]) },
|
|
17
17
|
verify_iss: ->(options) { options[:iss] && Claims::Issuer.new(issuers: options[:iss]) },
|
|
18
|
-
verify_iat: ->(
|
|
18
|
+
verify_iat: ->(options) { Claims::IssuedAt.new(leeway: options[:verify_iat].is_a?(Hash) ? options[:verify_iat][:leeway] : nil) },
|
|
19
19
|
verify_jti: ->(options) { Claims::JwtId.new(validator: options[:verify_jti]) },
|
|
20
20
|
verify_aud: ->(options) { options[:aud] && Claims::Audience.new(expected_audience: options[:aud]) },
|
|
21
21
|
verify_sub: ->(options) { options[:sub] && Claims::Subject.new(expected_subject: options[:sub]) },
|
data/lib/jwt/claims/issued_at.rb
CHANGED
|
@@ -4,6 +4,13 @@ module JWT
|
|
|
4
4
|
module Claims
|
|
5
5
|
# The IssuedAt class is responsible for validating the issued at claim ('iat') in a JWT token.
|
|
6
6
|
class IssuedAt
|
|
7
|
+
# Initializes a new IssuedAt instance.
|
|
8
|
+
#
|
|
9
|
+
# @param leeway [Integer] the drift (in seconds) to allow between the clock of the issuer and the clock of the verifier. Default: 0.
|
|
10
|
+
def initialize(leeway: 0)
|
|
11
|
+
@leeway = leeway || 0
|
|
12
|
+
end
|
|
13
|
+
|
|
7
14
|
# Verifies the issued at claim ('iat') in the JWT token.
|
|
8
15
|
#
|
|
9
16
|
# @param context [Object] the context containing the JWT payload.
|
|
@@ -15,8 +22,12 @@ module JWT
|
|
|
15
22
|
return unless context.payload.key?('iat')
|
|
16
23
|
|
|
17
24
|
iat = context.payload['iat']
|
|
18
|
-
raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(::Numeric) || iat.to_f > Time.now.to_f
|
|
25
|
+
raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(::Numeric) || iat.to_f > (Time.now.to_f + leeway)
|
|
19
26
|
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
attr_reader :leeway
|
|
20
31
|
end
|
|
21
32
|
end
|
|
22
33
|
end
|
data/lib/jwt/claims/verifier.rb
CHANGED
|
@@ -8,7 +8,7 @@ module JWT
|
|
|
8
8
|
exp: ->(options) { Claims::Expiration.new(leeway: options.dig(:exp, :leeway)) },
|
|
9
9
|
nbf: ->(options) { Claims::NotBefore.new(leeway: options.dig(:nbf, :leeway)) },
|
|
10
10
|
iss: ->(options) { Claims::Issuer.new(issuers: options[:iss]) },
|
|
11
|
-
iat: ->(
|
|
11
|
+
iat: ->(options) { Claims::IssuedAt.new(leeway: options.dig(:iat, :leeway)) },
|
|
12
12
|
jti: ->(options) { Claims::JwtId.new(validator: options[:jti]) },
|
|
13
13
|
aud: ->(options) { Claims::Audience.new(expected_audience: options[:aud]) },
|
|
14
14
|
sub: ->(options) { Claims::Subject.new(expected_subject: options[:sub]) },
|
|
@@ -33,8 +33,10 @@ module JWT
|
|
|
33
33
|
errors = []
|
|
34
34
|
iterate_verifiers(*options) do |verifier, verifier_options|
|
|
35
35
|
verify_one!(context, verifier, verifier_options)
|
|
36
|
-
rescue ::JWT::
|
|
37
|
-
|
|
36
|
+
rescue ::JWT::ClaimValidationError, ::JWT::MalformedTokenError => e
|
|
37
|
+
# A payload that cannot be decoded has no valid claims either, so the
|
|
38
|
+
# predicate API reports it instead of raising.
|
|
39
|
+
errors << JWT::Claims::Error.new(message: e.message)
|
|
38
40
|
end
|
|
39
41
|
errors
|
|
40
42
|
end
|
data/lib/jwt/claims.rb
CHANGED
|
@@ -41,7 +41,7 @@ module JWT
|
|
|
41
41
|
# @param payload [Hash] the JWT payload.
|
|
42
42
|
# @param options [Array] the options for verifying the claims.
|
|
43
43
|
# @return [void]
|
|
44
|
-
# @raise [JWT::
|
|
44
|
+
# @raise [JWT::ClaimValidationError] if any claim is invalid.
|
|
45
45
|
def verify_payload!(payload, *options)
|
|
46
46
|
Verifier.verify!(VerificationContext.new(payload: payload), *options)
|
|
47
47
|
end
|
|
@@ -11,7 +11,7 @@ module JWT
|
|
|
11
11
|
# @!attribute [rw] verify_iss
|
|
12
12
|
# @return [Boolean] whether to verify the issuer claim.
|
|
13
13
|
# @!attribute [rw] verify_iat
|
|
14
|
-
# @return [Boolean] whether to verify the issued at claim.
|
|
14
|
+
# @return [Boolean, Hash] whether to verify the issued at claim. A hash can be given to configure the claim, currently only `leeway` is supported.
|
|
15
15
|
# @!attribute [rw] verify_jti
|
|
16
16
|
# @return [Boolean] whether to verify the JWT ID claim.
|
|
17
17
|
# @!attribute [rw] verify_aud
|
data/lib/jwt/decode.rb
CHANGED
|
@@ -18,9 +18,9 @@ module JWT
|
|
|
18
18
|
# @param verify [Boolean] whether to verify the token's signature.
|
|
19
19
|
# @param options [Hash] additional options for decoding and verification.
|
|
20
20
|
# @param keyfinder [Proc] an optional key finder block to dynamically find the key for verification.
|
|
21
|
-
# @raise [JWT::
|
|
21
|
+
# @raise [JWT::Error] if decoding or verification fails.
|
|
22
22
|
def initialize(jwt, key, verify, options, &keyfinder)
|
|
23
|
-
raise JWT::
|
|
23
|
+
raise JWT::MalformedTokenError, 'Nil JSON web token' unless jwt
|
|
24
24
|
|
|
25
25
|
@token = EncodedToken.new(jwt)
|
|
26
26
|
@key = key
|
|
@@ -51,14 +51,14 @@ module JWT
|
|
|
51
51
|
def verify_signature
|
|
52
52
|
return if none_algorithm?
|
|
53
53
|
|
|
54
|
-
raise JWT::
|
|
54
|
+
raise JWT::SignatureError, 'No verification key available' unless @key
|
|
55
55
|
|
|
56
56
|
token.verify_signature!(algorithm: allowed_and_valid_algorithms, key: @key)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def verify_algo
|
|
60
60
|
raise JWT::IncorrectAlgorithm, 'An algorithm must be specified' if allowed_algorithms.empty?
|
|
61
|
-
raise JWT::
|
|
61
|
+
raise JWT::MalformedTokenError, 'Token header not a JSON object' unless valid_token_header?
|
|
62
62
|
raise JWT::IncorrectAlgorithm, 'Token is missing alg header' unless alg_in_header
|
|
63
63
|
raise JWT::IncorrectAlgorithm, 'Expected a different algorithm' if allowed_and_valid_algorithms.empty?
|
|
64
64
|
end
|
|
@@ -100,7 +100,7 @@ module JWT
|
|
|
100
100
|
# key can be of type [string, nil, OpenSSL::PKey, Array]
|
|
101
101
|
return key if key && !Array(key).empty?
|
|
102
102
|
|
|
103
|
-
raise JWT::
|
|
103
|
+
raise JWT::SignatureError, 'No verification key available'
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
def validate_segment_count!
|
|
@@ -109,7 +109,7 @@ module JWT
|
|
|
109
109
|
return if !@verify && segment_count == 2 # If no verifying required, the signature is not needed
|
|
110
110
|
return if segment_count == 2 && none_algorithm?
|
|
111
111
|
|
|
112
|
-
raise JWT::
|
|
112
|
+
raise JWT::MalformedTokenError, 'Not enough or too many segments'
|
|
113
113
|
end
|
|
114
114
|
|
|
115
115
|
def none_algorithm?
|
data/lib/jwt/encoded_token.rb
CHANGED
|
@@ -63,10 +63,10 @@ module JWT
|
|
|
63
63
|
# Returns the payload of the JWT token. Access requires the signature and claims to have been verified.
|
|
64
64
|
#
|
|
65
65
|
# @return [Hash] the payload.
|
|
66
|
-
# @raise [JWT::
|
|
66
|
+
# @raise [JWT::TokenError] if the signature has not been verified.
|
|
67
67
|
def payload
|
|
68
|
-
raise JWT::
|
|
69
|
-
raise JWT::
|
|
68
|
+
raise JWT::TokenError, 'Verify the token signature before accessing the payload' unless @signature_verified
|
|
69
|
+
raise JWT::TokenError, 'Verify the token claims before accessing the payload' unless @claims_verified
|
|
70
70
|
|
|
71
71
|
decoded_payload
|
|
72
72
|
end
|
|
@@ -77,10 +77,21 @@ module JWT
|
|
|
77
77
|
decoded_payload
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
#
|
|
80
|
+
# Returns the encoded payload of the JWT token.
|
|
81
81
|
#
|
|
82
82
|
# @return [String] the encoded payload.
|
|
83
|
-
|
|
83
|
+
attr_reader :encoded_payload
|
|
84
|
+
|
|
85
|
+
# Sets the encoded payload of the JWT token.
|
|
86
|
+
#
|
|
87
|
+
# Resets the verification state, requiring the token to be verified again.
|
|
88
|
+
#
|
|
89
|
+
# @param encoded_payload [String] the encoded payload.
|
|
90
|
+
def encoded_payload=(encoded_payload)
|
|
91
|
+
@encoded_payload = encoded_payload
|
|
92
|
+
@decoded_payload = nil
|
|
93
|
+
@signature_verified = @claims_verified = false
|
|
94
|
+
end
|
|
84
95
|
|
|
85
96
|
# Returns the signing input of the JWT token.
|
|
86
97
|
#
|
|
@@ -98,7 +109,7 @@ module JWT
|
|
|
98
109
|
# @param signature [Hash] the parameters for signature verification (see {#verify_signature!}).
|
|
99
110
|
# @param claims [Array<Symbol>, Hash] the claims to verify (see {#verify_claims!}).
|
|
100
111
|
# @return [nil]
|
|
101
|
-
# @raise [JWT::
|
|
112
|
+
# @raise [JWT::Error] if the signature or claim verification fails.
|
|
102
113
|
def verify!(signature:, claims: nil)
|
|
103
114
|
verify_signature!(**signature)
|
|
104
115
|
claims.is_a?(Array) ? verify_claims!(*claims) : verify_claims!(claims)
|
|
@@ -152,7 +163,8 @@ module JWT
|
|
|
152
163
|
|
|
153
164
|
# Verifies the claims of the token.
|
|
154
165
|
# @param options [Array<Symbol>, Hash] the claims to verify. By default, it checks the 'exp' claim.
|
|
155
|
-
# @raise [JWT::
|
|
166
|
+
# @raise [JWT::ClaimValidationError] if the claims are invalid.
|
|
167
|
+
# @raise [JWT::MalformedTokenError] if the payload cannot be decoded, which happens before any claim is validated.
|
|
156
168
|
def verify_claims!(*options)
|
|
157
169
|
Claims::Verifier.verify!(ClaimsContext.new(self), *claims_options(options)).tap do
|
|
158
170
|
@claims_verified = true
|
|
@@ -187,11 +199,11 @@ module JWT
|
|
|
187
199
|
end
|
|
188
200
|
|
|
189
201
|
def decode_payload
|
|
190
|
-
raise JWT::
|
|
202
|
+
raise JWT::MalformedTokenError, 'Encoded payload is empty' if encoded_payload == ''
|
|
191
203
|
|
|
192
204
|
if unencoded_payload?
|
|
193
205
|
verify_claims!(crit: ['b64'])
|
|
194
|
-
return
|
|
206
|
+
return parse(encoded_payload)
|
|
195
207
|
end
|
|
196
208
|
|
|
197
209
|
parse_and_decode(encoded_payload)
|
|
@@ -205,14 +217,10 @@ module JWT
|
|
|
205
217
|
parse(::JWT::Base64.url_decode(segment || ''))
|
|
206
218
|
end
|
|
207
219
|
|
|
208
|
-
def parse_unencoded(segment)
|
|
209
|
-
parse(segment)
|
|
210
|
-
end
|
|
211
|
-
|
|
212
220
|
def parse(segment)
|
|
213
221
|
JWT::JSON.parse(segment)
|
|
214
222
|
rescue ::JSON::ParserError
|
|
215
|
-
raise JWT::
|
|
223
|
+
raise JWT::MalformedTokenError, 'Invalid segment encoding'
|
|
216
224
|
end
|
|
217
225
|
|
|
218
226
|
def decoded_payload
|
data/lib/jwt/error.rb
CHANGED
|
@@ -1,54 +1,81 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JWT
|
|
4
|
+
# The base error class for all JWT errors.
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
|
|
4
7
|
# The EncodeError class is raised when there is an error encoding a JWT.
|
|
5
|
-
class EncodeError <
|
|
8
|
+
class EncodeError < Error; end
|
|
6
9
|
|
|
7
|
-
# The
|
|
8
|
-
class DecodeError
|
|
10
|
+
# The historical grouping of every error that is not an encoding error. Every
|
|
11
|
+
# error class below is a descendant, so `rescue JWT::DecodeError` keeps its
|
|
12
|
+
# original meaning.
|
|
13
|
+
#
|
|
14
|
+
# @deprecated Use {JWT::Error}, {JWT::TokenError} or a more specific error class instead.
|
|
15
|
+
class DecodeError < Error; end
|
|
9
16
|
|
|
10
|
-
# The
|
|
11
|
-
class
|
|
17
|
+
# The TokenError class is the base class for all errors related to token processing.
|
|
18
|
+
class TokenError < DecodeError; end
|
|
12
19
|
|
|
13
|
-
# The
|
|
14
|
-
class
|
|
20
|
+
# The MalformedTokenError class is raised when the token is structurally invalid.
|
|
21
|
+
class MalformedTokenError < TokenError; end
|
|
15
22
|
|
|
16
|
-
# The
|
|
17
|
-
class
|
|
23
|
+
# The Base64DecodeError class is raised when there is an error decoding a Base64-encoded string.
|
|
24
|
+
class Base64DecodeError < MalformedTokenError; end
|
|
18
25
|
|
|
19
|
-
# The
|
|
20
|
-
class
|
|
26
|
+
# The SignatureError class is the base class for signature and algorithm related errors.
|
|
27
|
+
class SignatureError < TokenError; end
|
|
21
28
|
|
|
22
|
-
# The
|
|
23
|
-
|
|
29
|
+
# The VerificationError class is raised when the signature of a token does not
|
|
30
|
+
# match the one calculated from the signing input.
|
|
31
|
+
class VerificationError < SignatureError; end
|
|
32
|
+
|
|
33
|
+
# The VerificationKeyError class is raised when the key or algorithm given for
|
|
34
|
+
# verification cannot be used, as opposed to a signature that does not match.
|
|
35
|
+
class VerificationKeyError < VerificationError; end
|
|
36
|
+
|
|
37
|
+
# The IncorrectAlgorithm class is raised when the JWT algorithm is incorrect.
|
|
38
|
+
class IncorrectAlgorithm < SignatureError; end
|
|
24
39
|
|
|
25
40
|
# The UnsupportedEcdsaCurve class is raised when the ECDSA curve is unsupported.
|
|
26
41
|
class UnsupportedEcdsaCurve < IncorrectAlgorithm; end
|
|
27
42
|
|
|
43
|
+
# The ClaimValidationError class is the base class for all claim validation errors.
|
|
44
|
+
class ClaimValidationError < TokenError; end
|
|
45
|
+
|
|
46
|
+
# The ExpiredSignature class is raised when the JWT token has expired.
|
|
47
|
+
class ExpiredSignature < ClaimValidationError; end
|
|
48
|
+
|
|
49
|
+
# The ImmatureSignature class is raised when the JWT token is not yet valid (nbf).
|
|
50
|
+
class ImmatureSignature < ClaimValidationError; end
|
|
51
|
+
|
|
52
|
+
# The InvalidIssuerError class is raised when the JWT issuer is invalid.
|
|
53
|
+
class InvalidIssuerError < ClaimValidationError; end
|
|
54
|
+
|
|
28
55
|
# The InvalidIatError class is raised when the JWT issued at (iat) claim is invalid.
|
|
29
|
-
class InvalidIatError <
|
|
56
|
+
class InvalidIatError < ClaimValidationError; end
|
|
30
57
|
|
|
31
58
|
# The InvalidAudError class is raised when the JWT audience (aud) claim is invalid.
|
|
32
|
-
class InvalidAudError <
|
|
59
|
+
class InvalidAudError < ClaimValidationError; end
|
|
33
60
|
|
|
34
61
|
# The InvalidSubError class is raised when the JWT subject (sub) claim is invalid.
|
|
35
|
-
class InvalidSubError <
|
|
62
|
+
class InvalidSubError < ClaimValidationError; end
|
|
36
63
|
|
|
37
64
|
# The InvalidCritError class is raised when the JWT crit header is invalid.
|
|
38
|
-
class InvalidCritError <
|
|
65
|
+
class InvalidCritError < ClaimValidationError; end
|
|
39
66
|
|
|
40
67
|
# The InvalidJtiError class is raised when the JWT ID (jti) claim is invalid.
|
|
41
|
-
class InvalidJtiError <
|
|
68
|
+
class InvalidJtiError < ClaimValidationError; end
|
|
42
69
|
|
|
43
70
|
# The InvalidPayload class is raised when the JWT payload is invalid.
|
|
44
|
-
class InvalidPayload <
|
|
71
|
+
class InvalidPayload < ClaimValidationError; end
|
|
45
72
|
|
|
46
73
|
# The MissingRequiredClaim class is raised when a required claim is missing from the JWT.
|
|
47
|
-
class MissingRequiredClaim <
|
|
48
|
-
|
|
49
|
-
# The Base64DecodeError class is raised when there is an error decoding a Base64-encoded string.
|
|
50
|
-
class Base64DecodeError < DecodeError; end
|
|
74
|
+
class MissingRequiredClaim < ClaimValidationError; end
|
|
51
75
|
|
|
52
76
|
# The JWKError class is raised when there is an error with the JSON Web Key (JWK).
|
|
53
77
|
class JWKError < DecodeError; end
|
|
78
|
+
|
|
79
|
+
# Raised when a JWK uses a key type (kty) that this library does not support.
|
|
80
|
+
class UnsupportedKeyType < JWKError; end
|
|
54
81
|
end
|
data/lib/jwt/jwa/ecdsa.rb
CHANGED
|
@@ -15,10 +15,8 @@ module JWT
|
|
|
15
15
|
raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::EC instance") unless signing_key.is_a?(::OpenSSL::PKey::EC)
|
|
16
16
|
raise_sign_error!('The given key is not a private key') unless signing_key.private?
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
key_algorithm
|
|
20
|
-
|
|
21
|
-
raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} signing key was provided" if alg != key_algorithm
|
|
18
|
+
key_algorithm = signing_key_algorithm(signing_key)
|
|
19
|
+
raise_sign_error!("payload algorithm is #{alg} but #{key_algorithm} signing key was provided") if alg != key_algorithm
|
|
22
20
|
|
|
23
21
|
asn1_to_raw(signing_key.dsa_sign_asn1(OpenSSL::Digest.new(digest).digest(data)), signing_key)
|
|
24
22
|
end
|
|
@@ -95,6 +93,13 @@ module JWT
|
|
|
95
93
|
self.class.curve_by_name(name)
|
|
96
94
|
end
|
|
97
95
|
|
|
96
|
+
# Signing-side counterpart of {.curve_by_name}. An unsupported curve on the
|
|
97
|
+
# signing key is an encoding problem, so it raises a JWT::EncodeError.
|
|
98
|
+
def signing_key_algorithm(signing_key)
|
|
99
|
+
curve_name = signing_key.group.curve_name
|
|
100
|
+
NAMED_CURVES.fetch(curve_name) { raise_sign_error!("The ECDSA curve '#{curve_name}' is not supported") }[:algorithm]
|
|
101
|
+
end
|
|
102
|
+
|
|
98
103
|
def raw_to_asn1(signature, private_key)
|
|
99
104
|
byte_size = (private_key.group.degree + 7) / 8
|
|
100
105
|
sig_bytes = signature[0..(byte_size - 1)]
|
data/lib/jwt/jwa/hmac.rb
CHANGED
|
@@ -21,15 +21,13 @@ module JWT
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def sign(data:, signing_key:)
|
|
24
|
-
|
|
25
|
-
validate_key_length!(signing_key)
|
|
24
|
+
validate_key!(signing_key) { |message| raise_sign_error!(message) }
|
|
26
25
|
|
|
27
26
|
OpenSSL::HMAC.digest(digest.new, signing_key, data)
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
def verify(data:, signature:, verification_key:)
|
|
31
|
-
|
|
32
|
-
validate_key_length!(verification_key)
|
|
30
|
+
validate_key!(verification_key) { |message| raise_verify_error!(message) }
|
|
33
31
|
|
|
34
32
|
SecurityUtils.secure_compare(signature, OpenSSL::HMAC.digest(digest.new, verification_key, data))
|
|
35
33
|
end
|
|
@@ -42,22 +40,20 @@ module JWT
|
|
|
42
40
|
|
|
43
41
|
attr_reader :digest
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
# Yields a message for the first problem found with the key. The caller
|
|
44
|
+
# raises it, so signing and verification failures keep their own error class.
|
|
45
|
+
def validate_key!(key)
|
|
46
|
+
yield 'HMAC key expected to be a String' unless key.is_a?(String)
|
|
47
|
+
yield 'HMAC key cannot be empty' if key.empty?
|
|
49
48
|
|
|
50
|
-
def validate_key_length!(key)
|
|
51
49
|
return unless JWT.configuration.decode.enforce_hmac_key_length
|
|
52
50
|
|
|
53
51
|
min_length = MIN_KEY_LENGTHS[alg]
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
raise_verify_error!("HMAC key must be at least #{min_length} bytes for #{alg} algorithm")
|
|
52
|
+
yield "HMAC key must be at least #{min_length} bytes for #{alg} algorithm" if key.bytesize < min_length
|
|
57
53
|
end
|
|
58
54
|
|
|
59
55
|
# Copy of https://github.com/rails/rails/blob/v7.0.3.1/activesupport/lib/active_support/security_utils.rb
|
|
60
|
-
# rubocop:disable Naming/MethodParameterName, Style/StringLiterals, Style/NumericPredicate
|
|
56
|
+
# rubocop:disable-next Naming/MethodParameterName, Style/StringLiterals, Style/NumericPredicate
|
|
61
57
|
module SecurityUtils
|
|
62
58
|
# Constant time string comparison, for fixed length strings.
|
|
63
59
|
#
|
|
@@ -73,7 +69,7 @@ module JWT
|
|
|
73
69
|
def fixed_length_secure_compare(a, b)
|
|
74
70
|
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
|
75
71
|
|
|
76
|
-
l = a.unpack
|
|
72
|
+
l = a.unpack("C#{a.bytesize}")
|
|
77
73
|
|
|
78
74
|
res = 0
|
|
79
75
|
b.each_byte { |byte| res |= byte ^ l.shift }
|
|
@@ -94,7 +90,6 @@ module JWT
|
|
|
94
90
|
end
|
|
95
91
|
module_function :secure_compare
|
|
96
92
|
end
|
|
97
|
-
# rubocop:enable Naming/MethodParameterName, Style/StringLiterals, Style/NumericPredicate
|
|
98
93
|
end
|
|
99
94
|
end
|
|
100
95
|
end
|
data/lib/jwt/jwa/ps.rb
CHANGED
|
@@ -13,12 +13,15 @@ module JWT
|
|
|
13
13
|
|
|
14
14
|
def sign(data:, signing_key:)
|
|
15
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)
|
|
16
|
+
raise_sign_error!('The given key is not a private key') unless signing_key.private?
|
|
16
17
|
raise_sign_error!('The key length must be greater than or equal to 2048 bits') if signing_key.n.num_bits < 2048
|
|
17
18
|
|
|
18
19
|
signing_key.sign_pss(digest_algorithm, data, salt_length: :digest, mgf1_hash: digest_algorithm)
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def verify(data:, signature:, verification_key:)
|
|
23
|
+
raise_verify_error!("The given key is a #{verification_key.class}. It has to be an OpenSSL::PKey::RSA instance") unless verification_key.is_a?(::OpenSSL::PKey::RSA)
|
|
24
|
+
|
|
22
25
|
verification_key.verify_pss(digest_algorithm, signature, data, salt_length: :auto, mgf1_hash: digest_algorithm)
|
|
23
26
|
rescue OpenSSL::PKey::PKeyError
|
|
24
27
|
raise JWT::VerificationError, 'Signature verification raised'
|
data/lib/jwt/jwa/rsa.rb
CHANGED
|
@@ -13,12 +13,15 @@ module JWT
|
|
|
13
13
|
|
|
14
14
|
def sign(data:, signing_key:)
|
|
15
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)
|
|
16
|
+
raise_sign_error!('The given key is not a private key') unless signing_key.private?
|
|
16
17
|
raise_sign_error!('The key length must be greater than or equal to 2048 bits') if signing_key.n.num_bits < 2048
|
|
17
18
|
|
|
18
19
|
signing_key.sign(OpenSSL::Digest.new(digest), data)
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def verify(data:, signature:, verification_key:)
|
|
23
|
+
raise_verify_error!("The given key is a #{verification_key.class}. It has to be an OpenSSL::PKey::RSA instance") unless verification_key.is_a?(::OpenSSL::PKey::RSA)
|
|
24
|
+
|
|
22
25
|
verification_key.verify(OpenSSL::Digest.new(digest), signature, data)
|
|
23
26
|
rescue OpenSSL::PKey::PKeyError
|
|
24
27
|
raise JWT::VerificationError, 'Signature verification raised'
|
data/lib/jwt/jwa/unsupported.rb
CHANGED
data/lib/jwt/jwa.rb
CHANGED
|
@@ -37,7 +37,7 @@ module JWT
|
|
|
37
37
|
# @api private
|
|
38
38
|
def create_signer(algorithm:, key:)
|
|
39
39
|
if key.is_a?(JWK::KeyBase)
|
|
40
|
-
validate_jwk_algorithms!(key, algorithm,
|
|
40
|
+
validate_jwk_algorithms!(key, algorithm, EncodeError)
|
|
41
41
|
|
|
42
42
|
return key
|
|
43
43
|
end
|
|
@@ -49,7 +49,7 @@ module JWT
|
|
|
49
49
|
def create_verifiers(algorithms:, keys:, preferred_algorithm:)
|
|
50
50
|
jwks, other_keys = keys.partition { |key| key.is_a?(JWK::KeyBase) }
|
|
51
51
|
|
|
52
|
-
validate_jwk_algorithms!(jwks, algorithms,
|
|
52
|
+
validate_jwk_algorithms!(jwks, algorithms, VerificationKeyError)
|
|
53
53
|
|
|
54
54
|
jwks + resolve_and_sort(algorithms: algorithms,
|
|
55
55
|
preferred_algorithm: preferred_algorithm)
|
data/lib/jwt/jwk/ec.rb
CHANGED
|
@@ -54,7 +54,7 @@ module JWT
|
|
|
54
54
|
|
|
55
55
|
def export(options = {})
|
|
56
56
|
exported = parameters.clone
|
|
57
|
-
exported.reject! { |k, _| EC_PRIVATE_KEY_ELEMENTS.include?
|
|
57
|
+
exported.reject! { |k, _| EC_PRIVATE_KEY_ELEMENTS.include?(k) } unless private? && options[:include_private] == true
|
|
58
58
|
exported
|
|
59
59
|
end
|
|
60
60
|
|
data/lib/jwt/jwk/hmac.rb
CHANGED
|
@@ -47,7 +47,7 @@ module JWT
|
|
|
47
47
|
# See https://tools.ietf.org/html/rfc7517#appendix-A.3
|
|
48
48
|
def export(options = {})
|
|
49
49
|
exported = parameters.clone
|
|
50
|
-
exported.reject! { |k, _| HMAC_PRIVATE_KEY_ELEMENTS.include?
|
|
50
|
+
exported.reject! { |k, _| HMAC_PRIVATE_KEY_ELEMENTS.include?(k) } unless private? && options[:include_private] == true
|
|
51
51
|
exported
|
|
52
52
|
end
|
|
53
53
|
|
data/lib/jwt/jwk/key_finder.rb
CHANGED
|
@@ -28,12 +28,12 @@ module JWT
|
|
|
28
28
|
# Returns the verification key for the given kid
|
|
29
29
|
# @param [String] kid the key id
|
|
30
30
|
def key_for(kid, key_field = :kid)
|
|
31
|
-
raise ::JWT::
|
|
31
|
+
raise ::JWT::MalformedTokenError, "Invalid type for #{key_field} header parameter" unless kid.nil? || kid.is_a?(String)
|
|
32
32
|
|
|
33
33
|
jwk = resolve_key(kid, key_field)
|
|
34
34
|
|
|
35
|
-
raise ::JWT::
|
|
36
|
-
raise ::JWT::
|
|
35
|
+
raise ::JWT::SignatureError, 'No keys found in jwks' unless @jwks.any?
|
|
36
|
+
raise ::JWT::SignatureError, "Could not find public key for kid #{kid}" unless jwk
|
|
37
37
|
|
|
38
38
|
jwk.verify_key
|
|
39
39
|
end
|
|
@@ -47,7 +47,7 @@ module JWT
|
|
|
47
47
|
return key_for(field_value, key_field) if field_value
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
raise ::JWT::
|
|
50
|
+
raise ::JWT::SignatureError, 'No key id (kid) or x5t found from token headers' unless @allow_nil_kid
|
|
51
51
|
|
|
52
52
|
kid = token.header['kid']
|
|
53
53
|
key_for(kid)
|
data/lib/jwt/jwk/rsa.rb
CHANGED
|
@@ -50,7 +50,7 @@ module JWT
|
|
|
50
50
|
|
|
51
51
|
def export(options = {})
|
|
52
52
|
exported = parameters.clone
|
|
53
|
-
exported.reject! { |k, _| RSA_PRIVATE_KEY_ELEMENTS.include?
|
|
53
|
+
exported.reject! { |k, _| RSA_PRIVATE_KEY_ELEMENTS.include?(k) } unless private? && options[:include_private] == true
|
|
54
54
|
|
|
55
55
|
exported
|
|
56
56
|
end
|
data/lib/jwt/jwk/set.rb
CHANGED
|
@@ -12,24 +12,24 @@ module JWT
|
|
|
12
12
|
|
|
13
13
|
attr_reader :keys
|
|
14
14
|
|
|
15
|
-
def initialize(jwks = nil, options = {})
|
|
16
|
-
jwks ||= {}
|
|
17
|
-
|
|
15
|
+
def initialize(jwks = nil, options = {})
|
|
18
16
|
@keys = case jwks
|
|
19
|
-
when
|
|
20
|
-
|
|
21
|
-
when JWT::JWK::KeyBase
|
|
22
|
-
|
|
23
|
-
when
|
|
24
|
-
|
|
25
|
-
[*jwks[:keys]].map { |k| JWT::JWK.new(k, nil, options) }
|
|
26
|
-
when Array
|
|
27
|
-
jwks.map { |k| JWT::JWK.new(k, nil, options) }
|
|
28
|
-
else
|
|
29
|
-
raise ArgumentError, 'Can only create new JWKS from Hash, Array and JWK'
|
|
17
|
+
when nil then []
|
|
18
|
+
when JWT::JWK::Set then jwks.keys.dup
|
|
19
|
+
when JWT::JWK::KeyBase then [jwks]
|
|
20
|
+
when Hash then build_supported_keys(jwks.transform_keys(&:to_sym)[:keys], options)
|
|
21
|
+
when Array then build_keys(jwks, options)
|
|
22
|
+
else raise ArgumentError, 'Can only create new JWKS from Hash, Array and JWK'
|
|
30
23
|
end
|
|
31
24
|
end
|
|
32
25
|
|
|
26
|
+
# Ensures a duplicated set owns its key collection. The keys themselves are
|
|
27
|
+
# intentionally shared; only the collection is copied.
|
|
28
|
+
def initialize_copy(other)
|
|
29
|
+
super
|
|
30
|
+
@keys = @keys.dup
|
|
31
|
+
end
|
|
32
|
+
|
|
33
33
|
def export(options = {})
|
|
34
34
|
{ keys: @keys.map { |k| k.export(options) } }
|
|
35
35
|
end
|
|
@@ -77,6 +77,20 @@ module JWT
|
|
|
77
77
|
alias | union
|
|
78
78
|
alias + union
|
|
79
79
|
alias << add
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def build_keys(keys, options)
|
|
84
|
+
[*keys].map { |key| JWT::JWK.new(key, nil, options) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def build_supported_keys(keys, options)
|
|
88
|
+
[*keys].each_with_object([]) do |key, arr|
|
|
89
|
+
arr << JWT::JWK.new(key, nil, options)
|
|
90
|
+
rescue JWT::UnsupportedKeyType
|
|
91
|
+
nil
|
|
92
|
+
end
|
|
93
|
+
end
|
|
80
94
|
end
|
|
81
95
|
end
|
|
82
96
|
end
|
data/lib/jwt/jwk.rb
CHANGED
|
@@ -13,7 +13,7 @@ module JWT
|
|
|
13
13
|
raise JWT::JWKError, 'Key type (kty) not provided' unless jwk_kty
|
|
14
14
|
|
|
15
15
|
return mappings.fetch(jwk_kty.to_s) do |kty|
|
|
16
|
-
raise JWT::
|
|
16
|
+
raise JWT::UnsupportedKeyType, "Key type #{kty} not supported"
|
|
17
17
|
end.new(key, params, options)
|
|
18
18
|
end
|
|
19
19
|
|
data/lib/jwt/token.rb
CHANGED
|
@@ -81,6 +81,7 @@ module JWT
|
|
|
81
81
|
#
|
|
82
82
|
def detach_payload!
|
|
83
83
|
@detached_payload = true
|
|
84
|
+
@jwt = nil
|
|
84
85
|
|
|
85
86
|
nil
|
|
86
87
|
end
|
|
@@ -104,7 +105,7 @@ module JWT
|
|
|
104
105
|
|
|
105
106
|
# Verifies the claims of the token.
|
|
106
107
|
# @param options [Array<Symbol>, Hash] the claims to verify.
|
|
107
|
-
# @raise [JWT::
|
|
108
|
+
# @raise [JWT::ClaimValidationError] if the claims are invalid.
|
|
108
109
|
def verify_claims!(*options)
|
|
109
110
|
Claims::Verifier.verify!(self, *options)
|
|
110
111
|
end
|
data/lib/jwt/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jwt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tim Rudat
|
|
@@ -202,7 +202,7 @@ licenses:
|
|
|
202
202
|
- MIT
|
|
203
203
|
metadata:
|
|
204
204
|
bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
|
|
205
|
-
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v3.
|
|
205
|
+
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v3.3.0/CHANGELOG.md
|
|
206
206
|
rubygems_mfa_required: 'true'
|
|
207
207
|
rdoc_options: []
|
|
208
208
|
require_paths:
|
|
@@ -218,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
218
218
|
- !ruby/object:Gem::Version
|
|
219
219
|
version: '0'
|
|
220
220
|
requirements: []
|
|
221
|
-
rubygems_version: 4.0.
|
|
221
|
+
rubygems_version: 4.0.16
|
|
222
222
|
specification_version: 4
|
|
223
223
|
summary: JSON Web Token implementation in Ruby
|
|
224
224
|
test_files: []
|