jwt 2.10.0 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/README.md +44 -54
- data/UPGRADING.md +46 -0
- data/lib/jwt/base64.rb +1 -10
- data/lib/jwt/claims/numeric.rb +0 -32
- data/lib/jwt/claims.rb +0 -7
- data/lib/jwt/configuration/container.rb +0 -1
- data/lib/jwt/decode.rb +5 -8
- data/lib/jwt/encoded_token.rb +71 -4
- data/lib/jwt/jwa/ecdsa.rb +0 -4
- data/lib/jwt/jwa/hmac.rb +0 -4
- data/lib/jwt/jwa/ps.rb +1 -0
- data/lib/jwt/jwa/rsa.rb +1 -0
- data/lib/jwt/jwa/signing_algorithm.rb +0 -1
- data/lib/jwt/jwa.rb +1 -26
- data/lib/jwt/jwk/ec.rb +0 -4
- data/lib/jwt/jwk/hmac.rb +2 -2
- data/lib/jwt/jwk/key_finder.rb +14 -1
- data/lib/jwt/jwk/rsa.rb +3 -0
- data/lib/jwt/jwk.rb +0 -1
- data/lib/jwt/token.rb +22 -3
- data/lib/jwt/version.rb +4 -22
- data/lib/jwt.rb +1 -7
- metadata +5 -17
- data/lib/jwt/claims/verification_methods.rb +0 -20
- data/lib/jwt/claims_validator.rb +0 -18
- data/lib/jwt/deprecations.rb +0 -49
- data/lib/jwt/jwa/compat.rb +0 -32
- data/lib/jwt/jwa/eddsa.rb +0 -35
- data/lib/jwt/jwa/hmac_rbnacl.rb +0 -50
- data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +0 -47
- data/lib/jwt/jwa/wrapper.rb +0 -44
- data/lib/jwt/jwk/okp_rbnacl.rb +0 -109
- data/lib/jwt/verify.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30b9373b7591af7e5e8ba0f049a2d41bc87afe0ea21462bd011f9558ec45e892
|
4
|
+
data.tar.gz: d5e77784a5eda9bae03f7bed74dabcfa81db1720057f742787c723d679d1005c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eafdd62f2eb9c35d2a27bf0429a866dd6f54b56c2650c373185f1c3e53ce08e06d03e5d8baba934493ea615cc9b86038d93a634509e5d932fdcbc91d669310e9
|
7
|
+
data.tar.gz: 68b004a6d858e2bfb78ba41017b19ec37b0dbed43525f63b9a743111f6d2f26eb4aea7a61ff2d2774645c504021d34ee8296cf342f36af97c426e96690ec08d7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,40 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.0.0](https://github.com/jwt/ruby-jwt/tree/v3.0.0) (NEXT)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.10.1...main)
|
6
|
+
|
7
|
+
**Breaking changes:**
|
8
|
+
- Require token signature to be verified before accessing payload [#648](https://github.com/jwt/ruby-jwt/pull/648) ([@anakinj](https://github.com/anakinj))
|
9
|
+
- Drop support for the HS512256 algorithm [#650](https://github.com/jwt/ruby-jwt/pull/650) ([@anakinj](https://github.com/anakinj))
|
10
|
+
- Remove deprecated claim verification methods [#654](https://github.com/jwt/ruby-jwt/pull/654) ([@anakinj](https://github.com/anakinj))
|
11
|
+
- Remove dependency to rbnacl [#655](https://github.com/jwt/ruby-jwt/pull/655) ([@anakinj](https://github.com/anakinj))
|
12
|
+
- Support only stricter base64 decoding (RFC 4648) [#658](https://github.com/jwt/ruby-jwt/pull/658) ([@anakinj](https://github.com/anakinj))
|
13
|
+
- Custom algorithms are required to include `JWT::JWA::SigningAlgorithm` [#660](https://github.com/jwt/ruby-jwt/pull/660) ([@anakinj](https://github.com/anakinj))
|
14
|
+
- Require RSA keys to be at least 2048 bits [#661](https://github.com/jwt/ruby-jwt/pull/661) ([@anakinj](https://github.com/anakinj))
|
15
|
+
- Base64 encode and decode the k value for HMAC JWKs [#662](https://github.com/jwt/ruby-jwt/pull/662) ([@anakinj](https://github.com/anakinj))
|
16
|
+
|
17
|
+
Take a look at the [upgrade guide](UPGRADING.md) for more details.
|
18
|
+
|
19
|
+
**Features:**
|
20
|
+
- JWT::EncodedToken#verify! method that bundles signature and claim validation [#647](https://github.com/jwt/ruby-jwt/pull/647) ([@anakinj](https://github.com/anakinj))
|
21
|
+
- Do not override the alg header if already given [#659](https://github.com/jwt/ruby-jwt/pull/659) ([@anakinj](https://github.com/anakinj))
|
22
|
+
- Make `JWK::KeyFinder` compatible with `JWT::EncodedToken` [#663](https://github.com/jwt/ruby-jwt/pull/663) ([@anakinj](https://github.com/anakinj))
|
23
|
+
- Your contribution here
|
24
|
+
|
25
|
+
**Fixes and enhancements:**
|
26
|
+
|
27
|
+
- Ruby 3.4 to CI matrix [#649](https://github.com/jwt/ruby-jwt/pull/649) ([@anakinj](https://github.com/anakinj))
|
28
|
+
- Your contribution here
|
29
|
+
|
30
|
+
## [v2.10.1](https://github.com/jwt/ruby-jwt/tree/v2.10.1) (2024-12-26)
|
31
|
+
|
32
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.10.0...v2.10.1)
|
33
|
+
|
34
|
+
**Fixes and enhancements:**
|
35
|
+
|
36
|
+
- Make version constants public again [#646](https://github.com/jwt/ruby-jwt/pull/646) ([@anakinj](https://github.com/anakinj))
|
37
|
+
|
3
38
|
## [v2.10.0](https://github.com/jwt/ruby-jwt/tree/v2.10.0) (2024-12-25)
|
4
39
|
|
5
40
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.9.3...v2.10.0)
|
data/README.md
CHANGED
@@ -14,25 +14,7 @@ See [CHANGELOG.md](CHANGELOG.md) for a complete set of changes.
|
|
14
14
|
|
15
15
|
## Upcoming breaking changes
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
- The indirect dependency to [rbnacl](https://github.com/RubyCrypto/rbnacl) will be removed:
|
20
|
-
- Support for the non-standard SHA512256 algorithm will be removed.
|
21
|
-
- Support for Ed25519 will be moved to a [separate gem](https://github.com/anakinj/jwt-eddsa) for better dependency handling.
|
22
|
-
|
23
|
-
- Base64 decoding will no longer fallback on the looser RFC 2045.
|
24
|
-
|
25
|
-
- Claim verification has been [split into separate classes](https://github.com/jwt/ruby-jwt/pull/605) and has [a new api](https://github.com/jwt/ruby-jwt/pull/626) and lead to the following deprecations:
|
26
|
-
- The `::JWT::ClaimsValidator` class will be removed in favor of the functionality provided by `::JWT::Claims`.
|
27
|
-
- The `::JWT::Claims::verify!` method will be removed in favor of `::JWT::Claims::verify_payload!`.
|
28
|
-
- The `::JWT::JWA.create` method will be removed.
|
29
|
-
- The `::JWT::Verify` class will be removed in favor of the functionality provided by `::JWT::Claims`.
|
30
|
-
- Calling `::JWT::Claims::Numeric.new` with a payload will be removed in favor of `::JWT::Claims::verify_payload!(payload, :numeric)`.
|
31
|
-
- Calling `::JWT::Claims::Numeric.verify!` with a payload will be removed in favor of `::JWT::Claims::verify_payload!(payload, :numeric)`.
|
32
|
-
|
33
|
-
- The internal algorithms were [restructured](https://github.com/jwt/ruby-jwt/pull/607) to support extensions from separate libraries. The changes lead to a few deprecations and new requirements:
|
34
|
-
- The `sign` and `verify` static methods on all the algorithms (`::JWT::JWA`) will be removed.
|
35
|
-
- Custom algorithms are expected to include the `JWT::JWA::SigningAlgorithm` module.
|
17
|
+
Check out breaking changes in the upcoming **version 3.0** from the [upgrade guide](UPGRADING.md)
|
36
18
|
|
37
19
|
## Sponsors
|
38
20
|
|
@@ -189,49 +171,18 @@ decoded_token = JWT.decode(token, ecdsa_key, true, { algorithm: 'ES256' })
|
|
189
171
|
puts decoded_token
|
190
172
|
```
|
191
173
|
|
192
|
-
### **
|
193
|
-
|
194
|
-
In order to use this algorithm you need to add the `RbNaCl` gem to you `Gemfile`.
|
195
|
-
|
196
|
-
```ruby
|
197
|
-
gem 'rbnacl'
|
198
|
-
```
|
199
|
-
|
200
|
-
For more detailed installation instruction check the official [repository](https://github.com/RubyCrypto/rbnacl) on GitHub.
|
201
|
-
|
202
|
-
* ED25519
|
203
|
-
|
204
|
-
```ruby
|
205
|
-
private_key = RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF')
|
206
|
-
public_key = private_key.verify_key
|
207
|
-
token = JWT.encode payload, private_key, 'ED25519'
|
208
|
-
|
209
|
-
# eyJhbGciOiJFRDI1NTE5In0.eyJkYXRhIjoidGVzdCJ9.6xIztXyOupskddGA_RvKU76V9b2dCQUYhoZEVFnRimJoPYIzZ2Fm47CWw8k2NTCNpgfAuxg9OXjaiVK7MvrbCQ
|
210
|
-
puts token
|
174
|
+
### **EdDSA**
|
211
175
|
|
212
|
-
|
213
|
-
# Array
|
214
|
-
# [
|
215
|
-
# {"test"=>"data"}, # payload
|
216
|
-
# {"alg"=>"ED25519"} # header
|
217
|
-
# ]
|
218
|
-
|
219
|
-
```
|
176
|
+
This algorithm has since version 3.0 been moved to the [jwt-eddsa](https://rubygems.org/gems/jwt-eddsa) gem.
|
220
177
|
|
221
178
|
### **RSASSA-PSS**
|
222
179
|
|
223
|
-
In order to use this algorithm you need to add the `openssl` gem to your `Gemfile` with a version greater or equal to `2.1`.
|
224
|
-
|
225
|
-
```ruby
|
226
|
-
gem 'openssl', '~> 2.1'
|
227
|
-
```
|
228
|
-
|
229
180
|
* PS256 - RSASSA-PSS using SHA-256 hash algorithm
|
230
181
|
* PS384 - RSASSA-PSS using SHA-384 hash algorithm
|
231
182
|
* PS512 - RSASSA-PSS using SHA-512 hash algorithm
|
232
183
|
|
233
184
|
```ruby
|
234
|
-
rsa_private = OpenSSL::PKey::RSA.generate
|
185
|
+
rsa_private = OpenSSL::PKey::RSA.generate(2048)
|
235
186
|
rsa_public = rsa_private.public_key
|
236
187
|
|
237
188
|
token = JWT.encode(payload, rsa_private, 'PS256')
|
@@ -254,7 +205,7 @@ Ruby-jwt gem supports custom [header fields](https://tools.ietf.org/html/rfc7519
|
|
254
205
|
To add custom header fields you need to pass `header_fields` parameter
|
255
206
|
|
256
207
|
```ruby
|
257
|
-
token = JWT.encode(payload, key,
|
208
|
+
token = JWT.encode(payload, key, 'HS256', header_fields={})
|
258
209
|
```
|
259
210
|
|
260
211
|
**Example:**
|
@@ -335,6 +286,45 @@ encoded_token.payload # => { 'exp'=>1234, 'jti'=>'1234", 'sub'=>'my-subject' }
|
|
335
286
|
encoded_token.header # {'kid'=>'hmac', 'alg'=>'HS256'}
|
336
287
|
```
|
337
288
|
|
289
|
+
The `JWT::EncodedToken#verify!` method can be used to verify signature and claim verification in one go. The `exp` claim is verified by default.
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
encoded_token = JWT::EncodedToken.new(token.jwt)
|
293
|
+
encoded_token.verify!(signature: {algorithm: 'HS256', key: "secret"})
|
294
|
+
|
295
|
+
encoded_token.payload # => { 'exp'=>1234, 'jti'=>'1234", 'sub'=>'my-subject' }
|
296
|
+
encoded_token.header # {'kid'=>'hmac', 'alg'=>'HS256'}
|
297
|
+
```
|
298
|
+
|
299
|
+
A keyfinder can be used to verify a signature. A keyfinder is an object responding to the `#call` method. The method expects to receive one argument, which is the token to be verified.
|
300
|
+
|
301
|
+
An example on using the built-in JWK keyfinder:
|
302
|
+
```ruby
|
303
|
+
# Create and sign a token
|
304
|
+
jwk = JWT::JWK.new(OpenSSL::PKey::RSA.generate(2048))
|
305
|
+
token = JWT::Token.new(payload: { pay: 'load' }, header: { kid: jwk.kid })
|
306
|
+
token.sign!(algorithm: 'RS256', key: jwk.signing_key)
|
307
|
+
|
308
|
+
# Create keyfinder object, verify and decode token
|
309
|
+
key_finder = JWT::JWK::KeyFinder.new(jwks: JWT::JWK::Set.new(jwk))
|
310
|
+
encoded_token = JWT::EncodedToken.new(token.jwt)
|
311
|
+
encoded_token.verify!(signature: { algorithm: 'RS256', key_finder: key_finder})
|
312
|
+
encoded_token.payload # => { 'pay' => 'load' }
|
313
|
+
```
|
314
|
+
|
315
|
+
Using a custom keyfinder proc:
|
316
|
+
```ruby
|
317
|
+
# Create and sign a token
|
318
|
+
key = OpenSSL::PKey::RSA.generate(2048)
|
319
|
+
token = JWT::Token.new(payload: { pay: 'load' })
|
320
|
+
token.sign!(algorithm: 'RS256', key: key)
|
321
|
+
|
322
|
+
# Verify and decode token
|
323
|
+
encoded_token = JWT::EncodedToken.new(token.jwt)
|
324
|
+
encoded_token.verify!(signature: { algorithm: 'RS256', key_finder: ->(_token){ key.public_key }})
|
325
|
+
encoded_token.payload # => { 'pay' => 'load' }
|
326
|
+
```
|
327
|
+
|
338
328
|
### Detached payload
|
339
329
|
|
340
330
|
The `::JWT::Token#detach_payload!` method can be use to detach the payload from the JWT.
|
data/UPGRADING.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Upgrading ruby-jwt to >= 3.0.0
|
2
|
+
|
3
|
+
## Removal of the indirect [RbNaCl](https://github.com/RubyCrypto/rbnacl) dependency
|
4
|
+
|
5
|
+
Historically, the set of supported algorithms was extended by including the `rbnacl` gem in the application's Gemfile. On load, ruby-jwt tried to load the gem and, if available, extend the algorithms to those provided by the `rbnacl/libsodium` libraries. This indirect dependency has caused some maintenance pain and confusion about which versions of the gem are supported.
|
6
|
+
|
7
|
+
Some work to ease the way alternative algorithms can be implemented has been done. This enables the extraction of the algorithm provided by `rbnacl`.
|
8
|
+
|
9
|
+
The extracted algorithms now live in the [jwt-eddsa](https://rubygems.org/gems/jwt-eddsa) gem.
|
10
|
+
|
11
|
+
### Dropped support for HS512256
|
12
|
+
|
13
|
+
The algorithm HS512256 (HMAC-SHA-512 truncated to 256-bits) is not part of any JWA/JWT RFC and therefore will not be supported anymore. It was part of the HMAC algorithms provided by the indirect [RbNaCl](https://github.com/RubyCrypto/rbnacl) dependency. Currently, there are no direct substitutes for the algorithm.
|
14
|
+
|
15
|
+
### `JWT::EncodedToken#payload` will raise before token is verified
|
16
|
+
|
17
|
+
To avoid accidental use of unverified tokens, the `JWT::EncodedToken#payload` method will raise an error if accessed before the token signature has been verified.
|
18
|
+
|
19
|
+
To access the payload before verification, use the method `JWT::EncodedToken#unverified_payload`.
|
20
|
+
|
21
|
+
## Stricter requirements on Base64 encoded data
|
22
|
+
|
23
|
+
Base64 decoding will no longer fallback on the looser RFC 2045. The biggest difference is that the looser version was ignoring whitespaces and newlines, whereas the stricter version raises errors in such cases.
|
24
|
+
|
25
|
+
If you, for example, read tokens from files, there could be problems with trailing newlines. Make sure you trim your input before passing it to the decoding mechanisms.
|
26
|
+
|
27
|
+
## Claim verification revamp
|
28
|
+
|
29
|
+
Claim verification has been [split into separate classes](https://github.com/jwt/ruby-jwt/pull/605) and has [a new API](https://github.com/jwt/ruby-jwt/pull/626), leading to the following deprecations:
|
30
|
+
|
31
|
+
- The `::JWT::ClaimsValidator` class will be removed in favor of the functionality provided by `::JWT::Claims`.
|
32
|
+
- The `::JWT::Claims::verify!` method will be removed in favor of `::JWT::Claims::verify_payload!`.
|
33
|
+
- The `::JWT::JWA.create` method will be removed.
|
34
|
+
- The `::JWT::Verify` class will be removed in favor of the functionality provided by `::JWT::Claims`.
|
35
|
+
- Calling `::JWT::Claims::Numeric.new` with a payload will be removed in favor of `::JWT::Claims::verify_payload!(payload, :numeric)`.
|
36
|
+
- Calling `::JWT::Claims::Numeric.verify!` with a payload will be removed in favor of `::JWT::Claims::verify_payload!(payload, :numeric)`.
|
37
|
+
|
38
|
+
## Algorithm restructuring
|
39
|
+
|
40
|
+
The internal algorithms were [restructured](https://github.com/jwt/ruby-jwt/pull/607) to support extensions from separate libraries. The changes led to a few deprecations and new requirements:
|
41
|
+
- The `sign` and `verify` static methods on all the algorithms (`::JWT::JWA`) will be removed.
|
42
|
+
- Custom algorithms are expected to include the `JWT::JWA::SigningAlgorithm` module.
|
43
|
+
|
44
|
+
## Base64 the `k´ value for HMAC JWKs
|
45
|
+
|
46
|
+
The gem was missing the Base64 encoding and decoding when representing and parsing a HMAC key as a JWK. This issue is now addressed. The added encoding will break compatibility with JWKs produced by older versions of the gem.
|
data/lib/jwt/base64.rb
CHANGED
@@ -14,22 +14,13 @@ module JWT
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# Decode a string with URL-safe Base64 complying with RFC 4648.
|
17
|
-
# Deprecated support for RFC 2045 remains for now. ("All line breaks or other characters not found in Table 1 must be ignored by decoding software")
|
18
17
|
# @api private
|
19
18
|
def url_decode(str)
|
20
19
|
::Base64.urlsafe_decode64(str)
|
21
20
|
rescue ArgumentError => e
|
22
21
|
raise unless e.message == 'invalid base64'
|
23
|
-
raise Base64DecodeError, 'Invalid base64 encoding' if JWT.configuration.strict_base64_decoding
|
24
22
|
|
25
|
-
|
26
|
-
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)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def loose_urlsafe_decode64(str)
|
31
|
-
str += '=' * (4 - str.length.modulo(4))
|
32
|
-
::Base64.decode64(str.tr('-_', '+/'))
|
23
|
+
raise Base64DecodeError, 'Invalid base64 encoding'
|
33
24
|
end
|
34
25
|
end
|
35
26
|
end
|
data/lib/jwt/claims/numeric.rb
CHANGED
@@ -5,18 +5,6 @@ module JWT
|
|
5
5
|
# The Numeric class is responsible for validating numeric claims in a JWT token.
|
6
6
|
# The numeric claims are: exp, iat and nbf
|
7
7
|
class Numeric
|
8
|
-
# The Compat class provides backward compatibility for numeric claim validation.
|
9
|
-
# @api private
|
10
|
-
class Compat
|
11
|
-
def initialize(payload)
|
12
|
-
@payload = payload
|
13
|
-
end
|
14
|
-
|
15
|
-
def verify!
|
16
|
-
JWT::Claims.verify_payload!(@payload, :numeric)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
8
|
# List of numeric claims that can be validated.
|
21
9
|
NUMERIC_CLAIMS = %i[
|
22
10
|
exp
|
@@ -26,14 +14,6 @@ module JWT
|
|
26
14
|
|
27
15
|
private_constant(:NUMERIC_CLAIMS)
|
28
16
|
|
29
|
-
# @api private
|
30
|
-
def self.new(*args)
|
31
|
-
return super if args.empty?
|
32
|
-
|
33
|
-
Deprecations.warning('Calling ::JWT::Claims::Numeric.new with the payload will be removed in the next major version of ruby-jwt')
|
34
|
-
Compat.new(*args)
|
35
|
-
end
|
36
|
-
|
37
17
|
# Verifies the numeric claims in the JWT context.
|
38
18
|
#
|
39
19
|
# @param context [Object] the context containing the JWT payload.
|
@@ -43,18 +23,6 @@ module JWT
|
|
43
23
|
validate_numeric_claims(context.payload)
|
44
24
|
end
|
45
25
|
|
46
|
-
# Verifies the numeric claims in the JWT payload.
|
47
|
-
#
|
48
|
-
# @param payload [Hash] the JWT payload containing the claims.
|
49
|
-
# @param _args [Hash] additional arguments (not used).
|
50
|
-
# @raise [JWT::InvalidClaimError] if any numeric claim is invalid.
|
51
|
-
# @return [nil]
|
52
|
-
# @deprecated The ::JWT::Claims::Numeric.verify! method will be removed in the next major version of ruby-jwt
|
53
|
-
def self.verify!(payload:, **_args)
|
54
|
-
Deprecations.warning('The ::JWT::Claims::Numeric.verify! method will be removed in the next major version of ruby-jwt.')
|
55
|
-
JWT::Claims.verify_payload!(payload, :numeric)
|
56
|
-
end
|
57
|
-
|
58
26
|
private
|
59
27
|
|
60
28
|
def validate_numeric_claims(payload)
|
data/lib/jwt/claims.rb
CHANGED
@@ -11,7 +11,6 @@ require_relative 'claims/not_before'
|
|
11
11
|
require_relative 'claims/numeric'
|
12
12
|
require_relative 'claims/required'
|
13
13
|
require_relative 'claims/subject'
|
14
|
-
require_relative 'claims/verification_methods'
|
15
14
|
require_relative 'claims/verifier'
|
16
15
|
|
17
16
|
module JWT
|
@@ -33,12 +32,6 @@ module JWT
|
|
33
32
|
Error = Struct.new(:message, keyword_init: true)
|
34
33
|
|
35
34
|
class << self
|
36
|
-
# @deprecated Use {verify_payload!} instead. Will be removed in the next major version of ruby-jwt.
|
37
|
-
def verify!(payload, options)
|
38
|
-
Deprecations.warning('The ::JWT::Claims.verify! method is deprecated will be removed in the next major version of ruby-jwt')
|
39
|
-
DecodeVerifier.verify!(payload, options)
|
40
|
-
end
|
41
|
-
|
42
35
|
# Checks if the claims in the JWT payload are valid.
|
43
36
|
# @example
|
44
37
|
#
|
data/lib/jwt/decode.rb
CHANGED
@@ -33,10 +33,10 @@ module JWT
|
|
33
33
|
verify_algo
|
34
34
|
set_key
|
35
35
|
verify_signature
|
36
|
-
Claims::DecodeVerifier.verify!(token.
|
36
|
+
Claims::DecodeVerifier.verify!(token.unverified_payload, @options)
|
37
37
|
end
|
38
38
|
|
39
|
-
[token.
|
39
|
+
[token.unverified_payload, token.header]
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
@@ -77,11 +77,8 @@ module JWT
|
|
77
77
|
:algorithms].freeze
|
78
78
|
|
79
79
|
def given_algorithms
|
80
|
-
ALGORITHM_KEYS.
|
81
|
-
|
82
|
-
return Array(alg) if alg
|
83
|
-
end
|
84
|
-
[]
|
80
|
+
alg_key = ALGORITHM_KEYS.find { |key| @options[key] }
|
81
|
+
Array(@options[alg_key])
|
85
82
|
end
|
86
83
|
|
87
84
|
def allowed_algorithms
|
@@ -93,7 +90,7 @@ module JWT
|
|
93
90
|
end
|
94
91
|
|
95
92
|
def find_key(&keyfinder)
|
96
|
-
key = (keyfinder.arity == 2 ? yield(token.header, token.
|
93
|
+
key = (keyfinder.arity == 2 ? yield(token.header, token.unverified_payload) : yield(token.header))
|
97
94
|
# key can be of type [string, nil, OpenSSL::PKey, Array]
|
98
95
|
return key if key && !Array(key).empty?
|
99
96
|
|
data/lib/jwt/encoded_token.rb
CHANGED
@@ -12,7 +12,21 @@ module JWT
|
|
12
12
|
# encoded_token.verify_signature!(algorithm: 'HS256', key: 'secret')
|
13
13
|
# encoded_token.payload # => {'pay' => 'load'}
|
14
14
|
class EncodedToken
|
15
|
-
|
15
|
+
# @private
|
16
|
+
# Allow access to the unverified payload for claim verification.
|
17
|
+
class ClaimsContext
|
18
|
+
extend Forwardable
|
19
|
+
|
20
|
+
def_delegators :@token, :header, :unverified_payload
|
21
|
+
|
22
|
+
def initialize(token)
|
23
|
+
@token = token
|
24
|
+
end
|
25
|
+
|
26
|
+
def payload
|
27
|
+
unverified_payload
|
28
|
+
end
|
29
|
+
end
|
16
30
|
|
17
31
|
# Returns the original token provided to the class.
|
18
32
|
# @return [String] The JWT token.
|
@@ -26,6 +40,7 @@ module JWT
|
|
26
40
|
raise ArgumentError, 'Provided JWT must be a String' unless jwt.is_a?(String)
|
27
41
|
|
28
42
|
@jwt = jwt
|
43
|
+
@signature_verified = false
|
29
44
|
@encoded_header, @encoded_payload, @encoded_signature = jwt.split('.')
|
30
45
|
end
|
31
46
|
|
@@ -53,11 +68,20 @@ module JWT
|
|
53
68
|
# @return [String] the encoded header.
|
54
69
|
attr_reader :encoded_header
|
55
70
|
|
56
|
-
# Returns the payload of the JWT token.
|
71
|
+
# Returns the payload of the JWT token. Access requires the signature to have been verified.
|
57
72
|
#
|
58
73
|
# @return [Hash] the payload.
|
74
|
+
# @raise [JWT::DecodeError] if the signature has not been verified.
|
59
75
|
def payload
|
60
|
-
|
76
|
+
raise JWT::DecodeError, 'Verify the token signature before accessing the payload' unless @signature_verified
|
77
|
+
|
78
|
+
decoded_payload
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the payload of the JWT token without requiring the signature to have been verified.
|
82
|
+
# @return [Hash] the payload.
|
83
|
+
def unverified_payload
|
84
|
+
decoded_payload
|
61
85
|
end
|
62
86
|
|
63
87
|
# Sets or returns the encoded payload of the JWT token.
|
@@ -72,6 +96,22 @@ module JWT
|
|
72
96
|
[encoded_header, encoded_payload].join('.')
|
73
97
|
end
|
74
98
|
|
99
|
+
# Verifies the token signature and claims.
|
100
|
+
# By default it verifies the 'exp' claim.
|
101
|
+
#
|
102
|
+
# @example
|
103
|
+
# encoded_token.verify!(signature: { algorithm: 'HS256', key: 'secret' }, claims: [:exp])
|
104
|
+
#
|
105
|
+
# @param signature [Hash] the parameters for signature verification (see {#verify_signature!}).
|
106
|
+
# @param claims [Array<Symbol>, Hash] the claims to verify (see {#verify_claims!}).
|
107
|
+
# @return [nil]
|
108
|
+
# @raise [JWT::DecodeError] if the signature or claim verification fails.
|
109
|
+
def verify!(signature:, claims: [:exp])
|
110
|
+
verify_signature!(**signature)
|
111
|
+
claims.is_a?(Array) ? verify_claims!(*claims) : verify_claims!(claims)
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
75
115
|
# Verifies the signature of the JWT token.
|
76
116
|
#
|
77
117
|
# @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.
|
@@ -96,11 +136,34 @@ module JWT
|
|
96
136
|
# @param key [String, Array<String>] the key(s) to use for verification.
|
97
137
|
# @return [Boolean] true if the signature is valid, false otherwise.
|
98
138
|
def valid_signature?(algorithm:, key:)
|
99
|
-
Array(JWA.resolve_and_sort(algorithms: algorithm, preferred_algorithm: header['alg'])).any? do |algo|
|
139
|
+
valid = Array(JWA.resolve_and_sort(algorithms: algorithm, preferred_algorithm: header['alg'])).any? do |algo|
|
100
140
|
Array(key).any? do |one_key|
|
101
141
|
algo.verify(data: signing_input, signature: signature, verification_key: one_key)
|
102
142
|
end
|
103
143
|
end
|
144
|
+
|
145
|
+
valid.tap { |verified| @signature_verified = verified }
|
146
|
+
end
|
147
|
+
|
148
|
+
# Verifies the claims of the token.
|
149
|
+
# @param options [Array<Symbol>, Hash] the claims to verify.
|
150
|
+
# @raise [JWT::DecodeError] if the claims are invalid.
|
151
|
+
def verify_claims!(*options)
|
152
|
+
Claims::Verifier.verify!(ClaimsContext.new(self), *options)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns the errors of the claims of the token.
|
156
|
+
# @param options [Array<Symbol>, Hash] the claims to verify.
|
157
|
+
# @return [Array<Symbol>] the errors of the claims.
|
158
|
+
def claim_errors(*options)
|
159
|
+
Claims::Verifier.errors(ClaimsContext.new(self), *options)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns whether the claims of the token are valid.
|
163
|
+
# @param options [Array<Symbol>, Hash] the claims to verify.
|
164
|
+
# @return [Boolean] whether the claims are valid.
|
165
|
+
def valid_claims?(*options)
|
166
|
+
claim_errors(*options).empty?
|
104
167
|
end
|
105
168
|
|
106
169
|
alias to_s jwt
|
@@ -135,5 +198,9 @@ module JWT
|
|
135
198
|
rescue ::JSON::ParserError
|
136
199
|
raise JWT::DecodeError, 'Invalid segment encoding'
|
137
200
|
end
|
201
|
+
|
202
|
+
def decoded_payload
|
203
|
+
@decoded_payload ||= decode_payload
|
204
|
+
end
|
138
205
|
end
|
139
206
|
end
|
data/lib/jwt/jwa/ecdsa.rb
CHANGED
@@ -56,10 +56,6 @@ module JWT
|
|
56
56
|
register_algorithm(new(v[:algorithm], v[:digest]))
|
57
57
|
end
|
58
58
|
|
59
|
-
def self.from_algorithm(algorithm)
|
60
|
-
new(algorithm, algorithm.downcase.gsub('es', 'sha'))
|
61
|
-
end
|
62
|
-
|
63
59
|
def self.curve_by_name(name)
|
64
60
|
NAMED_CURVES.fetch(name) do
|
65
61
|
raise UnsupportedEcdsaCurve, "The ECDSA curve '#{name}' is not supported"
|
data/lib/jwt/jwa/hmac.rb
CHANGED
data/lib/jwt/jwa/ps.rb
CHANGED
@@ -13,6 +13,7 @@ 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 key length must be greater than or equal to 2048 bits') if signing_key.n.num_bits < 2048
|
16
17
|
|
17
18
|
signing_key.sign_pss(digest_algorithm, data, salt_length: :digest, mgf1_hash: digest_algorithm)
|
18
19
|
end
|
data/lib/jwt/jwa/rsa.rb
CHANGED
@@ -13,6 +13,7 @@ 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 key length must be greater than or equal to 2048 bits') if signing_key.n.num_bits < 2048
|
16
17
|
|
17
18
|
signing_key.sign(digest, data)
|
18
19
|
end
|
data/lib/jwt/jwa.rb
CHANGED
@@ -2,13 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'openssl'
|
4
4
|
|
5
|
-
begin
|
6
|
-
require 'rbnacl'
|
7
|
-
rescue LoadError
|
8
|
-
raise if defined?(RbNaCl)
|
9
|
-
end
|
10
|
-
|
11
|
-
require_relative 'jwa/compat'
|
12
5
|
require_relative 'jwa/signing_algorithm'
|
13
6
|
require_relative 'jwa/ecdsa'
|
14
7
|
require_relative 'jwa/hmac'
|
@@ -16,15 +9,6 @@ require_relative 'jwa/none'
|
|
16
9
|
require_relative 'jwa/ps'
|
17
10
|
require_relative 'jwa/rsa'
|
18
11
|
require_relative 'jwa/unsupported'
|
19
|
-
require_relative 'jwa/wrapper'
|
20
|
-
|
21
|
-
require_relative 'jwa/eddsa' if JWT.rbnacl?
|
22
|
-
|
23
|
-
if JWT.rbnacl_6_or_greater?
|
24
|
-
require_relative 'jwa/hmac_rbnacl'
|
25
|
-
elsif JWT.rbnacl?
|
26
|
-
require_relative 'jwa/hmac_rbnacl_fixed'
|
27
|
-
end
|
28
12
|
|
29
13
|
module JWT
|
30
14
|
# The JWA module contains all supported algorithms.
|
@@ -34,10 +18,7 @@ module JWT
|
|
34
18
|
def resolve(algorithm)
|
35
19
|
return find(algorithm) if algorithm.is_a?(String) || algorithm.is_a?(Symbol)
|
36
20
|
|
37
|
-
unless algorithm.is_a?(SigningAlgorithm)
|
38
|
-
Deprecations.warning('Custom algorithms are required to include JWT::JWA::SigningAlgorithm. Custom algorithms that do not include this module may stop working in the next major version of ruby-jwt.')
|
39
|
-
return Wrapper.new(algorithm)
|
40
|
-
end
|
21
|
+
raise ArgumentError, 'Custom algorithms are required to include JWT::JWA::SigningAlgorithm' unless algorithm.is_a?(SigningAlgorithm)
|
41
22
|
|
42
23
|
algorithm
|
43
24
|
end
|
@@ -47,12 +28,6 @@ module JWT
|
|
47
28
|
algs = Array(algorithms).map { |alg| JWA.resolve(alg) }
|
48
29
|
algs.partition { |alg| alg.valid_alg?(preferred_algorithm) }.flatten
|
49
30
|
end
|
50
|
-
|
51
|
-
# @deprecated The `::JWT::JWA.create` method is deprecated and will be removed in the next major version of ruby-jwt.
|
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.')
|
54
|
-
resolve(algorithm)
|
55
|
-
end
|
56
31
|
end
|
57
32
|
end
|
58
33
|
end
|
data/lib/jwt/jwk/ec.rb
CHANGED
@@ -124,10 +124,6 @@ module JWT
|
|
124
124
|
::JWT::Base64.url_encode(octets)
|
125
125
|
end
|
126
126
|
|
127
|
-
def encode_open_ssl_bn(key_part)
|
128
|
-
::JWT::Base64.url_encode(key_part.to_s(BINARY))
|
129
|
-
end
|
130
|
-
|
131
127
|
def parse_ec_key(key)
|
132
128
|
crv, x_octets, y_octets = keypair_components(key)
|
133
129
|
octets = key.private_key&.to_bn&.to_s(BINARY)
|
data/lib/jwt/jwk/hmac.rb
CHANGED
@@ -70,7 +70,7 @@ module JWT
|
|
70
70
|
private
|
71
71
|
|
72
72
|
def secret
|
73
|
-
self[:k]
|
73
|
+
@secret ||= ::JWT::Base64.url_decode(self[:k])
|
74
74
|
end
|
75
75
|
|
76
76
|
def extract_key_params(key)
|
@@ -78,7 +78,7 @@ module JWT
|
|
78
78
|
when JWT::JWK::HMAC
|
79
79
|
key.export(include_private: true)
|
80
80
|
when String # Accept String key as input
|
81
|
-
{ kty: KTY, k: key }
|
81
|
+
{ kty: KTY, k: ::JWT::Base64.url_encode(key) }
|
82
82
|
when Hash
|
83
83
|
key.transform_keys(&:to_sym)
|
84
84
|
else
|