jwt 2.9.3 → 3.1.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 +108 -47
- data/CODE_OF_CONDUCT.md +14 -14
- data/CONTRIBUTING.md +9 -10
- data/README.md +273 -234
- data/UPGRADING.md +47 -0
- data/lib/jwt/base64.rb +4 -10
- data/lib/jwt/claims/audience.rb +10 -0
- data/lib/jwt/claims/crit.rb +35 -0
- data/lib/jwt/claims/decode_verifier.rb +3 -3
- data/lib/jwt/claims/expiration.rb +10 -0
- data/lib/jwt/claims/issued_at.rb +7 -0
- data/lib/jwt/claims/issuer.rb +10 -0
- data/lib/jwt/claims/jwt_id.rb +10 -0
- data/lib/jwt/claims/not_before.rb +10 -0
- data/lib/jwt/claims/numeric.rb +9 -19
- data/lib/jwt/claims/required.rb +10 -0
- data/lib/jwt/claims/subject.rb +10 -0
- data/lib/jwt/claims/verifier.rb +6 -7
- data/lib/jwt/claims.rb +4 -19
- data/lib/jwt/configuration/container.rb +20 -1
- data/lib/jwt/configuration/decode_configuration.rb +24 -0
- data/lib/jwt/configuration/jwk_configuration.rb +1 -0
- data/lib/jwt/configuration.rb +8 -0
- data/lib/jwt/decode.rb +42 -79
- data/lib/jwt/encode.rb +17 -56
- data/lib/jwt/encoded_token.rb +236 -0
- data/lib/jwt/error.rb +32 -1
- data/lib/jwt/json.rb +1 -1
- data/lib/jwt/jwa/ecdsa.rb +31 -13
- data/lib/jwt/jwa/hmac.rb +2 -7
- data/lib/jwt/jwa/none.rb +1 -0
- data/lib/jwt/jwa/ps.rb +3 -3
- data/lib/jwt/jwa/rsa.rb +6 -6
- data/lib/jwt/jwa/signing_algorithm.rb +3 -1
- data/lib/jwt/jwa/unsupported.rb +1 -0
- data/lib/jwt/jwa.rb +77 -24
- data/lib/jwt/jwk/ec.rb +54 -65
- data/lib/jwt/jwk/hmac.rb +5 -6
- data/lib/jwt/jwk/key_base.rb +16 -1
- data/lib/jwt/jwk/key_finder.rb +35 -8
- data/lib/jwt/jwk/kid_as_key_digest.rb +1 -0
- data/lib/jwt/jwk/rsa.rb +7 -4
- data/lib/jwt/jwk/set.rb +2 -0
- data/lib/jwt/jwk.rb +1 -1
- data/lib/jwt/token.rb +131 -0
- data/lib/jwt/version.rb +24 -19
- data/lib/jwt.rb +17 -7
- data/ruby-jwt.gemspec +2 -0
- metadata +36 -16
- data/lib/jwt/claims_validator.rb +0 -16
- data/lib/jwt/deprecations.rb +0 -48
- data/lib/jwt/jwa/compat.rb +0 -29
- data/lib/jwt/jwa/eddsa.rb +0 -34
- data/lib/jwt/jwa/hmac_rbnacl.rb +0 -49
- data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +0 -46
- data/lib/jwt/jwa/wrapper.rb +0 -43
- data/lib/jwt/jwk/okp_rbnacl.rb +0 -110
- data/lib/jwt/verify.rb +0 -34
data/UPGRADING.md
ADDED
@@ -0,0 +1,47 @@
|
|
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
|
+
|
42
|
+
- The `sign` and `verify` static methods on all the algorithms (`::JWT::JWA`) will be removed.
|
43
|
+
- Custom algorithms are expected to include the `JWT::JWA::SigningAlgorithm` module.
|
44
|
+
|
45
|
+
## Base64 the `k´ value for HMAC JWKs
|
46
|
+
|
47
|
+
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
@@ -4,29 +4,23 @@ require 'base64'
|
|
4
4
|
|
5
5
|
module JWT
|
6
6
|
# Base64 encoding and decoding
|
7
|
+
# @api private
|
7
8
|
class Base64
|
8
9
|
class << self
|
9
10
|
# Encode a string with URL-safe Base64 complying with RFC 4648 (not padded).
|
11
|
+
# @api private
|
10
12
|
def url_encode(str)
|
11
13
|
::Base64.urlsafe_encode64(str, padding: false)
|
12
14
|
end
|
13
15
|
|
14
16
|
# Decode a string with URL-safe Base64 complying with RFC 4648.
|
15
|
-
#
|
17
|
+
# @api private
|
16
18
|
def url_decode(str)
|
17
19
|
::Base64.urlsafe_decode64(str)
|
18
20
|
rescue ArgumentError => e
|
19
21
|
raise unless e.message == 'invalid base64'
|
20
|
-
raise Base64DecodeError, 'Invalid base64 encoding' if JWT.configuration.strict_base64_decoding
|
21
22
|
|
22
|
-
|
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
|
25
|
-
end
|
26
|
-
|
27
|
-
def loose_urlsafe_decode64(str)
|
28
|
-
str += '=' * (4 - str.length.modulo(4))
|
29
|
-
::Base64.decode64(str.tr('-_', '+/'))
|
23
|
+
raise Base64DecodeError, 'Invalid base64 encoding'
|
30
24
|
end
|
31
25
|
end
|
32
26
|
end
|
data/lib/jwt/claims/audience.rb
CHANGED
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The Audience class is responsible for validating the audience claim ('aud') in a JWT token.
|
5
6
|
class Audience
|
7
|
+
# Initializes a new Audience instance.
|
8
|
+
#
|
9
|
+
# @param expected_audience [String, Array<String>] the expected audience(s) for the JWT token.
|
6
10
|
def initialize(expected_audience:)
|
7
11
|
@expected_audience = expected_audience
|
8
12
|
end
|
9
13
|
|
14
|
+
# Verifies the audience claim ('aud') in the JWT token.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::InvalidAudError] if the audience claim is invalid.
|
19
|
+
# @return [nil]
|
10
20
|
def verify!(context:, **_args)
|
11
21
|
aud = context.payload['aud']
|
12
22
|
raise JWT::InvalidAudError, "Invalid audience. Expected #{expected_audience}, received #{aud || '<none>'}" if ([*aud] & [*expected_audience]).empty?
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module Claims
|
5
|
+
# Responsible of validation the crit header
|
6
|
+
class Crit
|
7
|
+
# Initializes a new Crit instance.
|
8
|
+
#
|
9
|
+
# @param expected_crits [String] the expected crit header values for the JWT token.
|
10
|
+
def initialize(expected_crits:)
|
11
|
+
@expected_crits = Array(expected_crits)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Verifies the critical claim ('crit') in the JWT token header.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload and header.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::InvalidCritError] if the crit claim is invalid.
|
19
|
+
# @return [nil]
|
20
|
+
def verify!(context:, **_args)
|
21
|
+
raise(JWT::InvalidCritError, 'Crit header missing') unless context.header['crit']
|
22
|
+
raise(JWT::InvalidCritError, 'Crit header should be an array') unless context.header['crit'].is_a?(Array)
|
23
|
+
|
24
|
+
missing = (expected_crits - context.header['crit'])
|
25
|
+
raise(JWT::InvalidCritError, "Crit header missing expected values: #{missing.join(', ')}") if missing.any?
|
26
|
+
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :expected_crits
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -4,12 +4,12 @@ module JWT
|
|
4
4
|
module Claims
|
5
5
|
# Context class to contain the data passed to individual claim validators
|
6
6
|
#
|
7
|
-
# @private
|
7
|
+
# @api private
|
8
8
|
VerificationContext = Struct.new(:payload, keyword_init: true)
|
9
9
|
|
10
10
|
# Verifiers to support the ::JWT.decode method
|
11
11
|
#
|
12
|
-
# @private
|
12
|
+
# @api private
|
13
13
|
module DecodeVerifier
|
14
14
|
VERIFIERS = {
|
15
15
|
verify_expiration: ->(options) { Claims::Expiration.new(leeway: options[:exp_leeway] || options[:leeway]) },
|
@@ -25,7 +25,7 @@ module JWT
|
|
25
25
|
private_constant(:VERIFIERS)
|
26
26
|
|
27
27
|
class << self
|
28
|
-
# @private
|
28
|
+
# @api private
|
29
29
|
def verify!(payload, options)
|
30
30
|
VERIFIERS.each do |key, verifier_builder|
|
31
31
|
next unless options[key] || options[key.to_s]
|
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The Expiration class is responsible for validating the expiration claim ('exp') in a JWT token.
|
5
6
|
class Expiration
|
7
|
+
# Initializes a new Expiration instance.
|
8
|
+
#
|
9
|
+
# @param leeway [Integer] the amount of leeway (in seconds) to allow when validating the expiration time. Default: 0.
|
6
10
|
def initialize(leeway:)
|
7
11
|
@leeway = leeway || 0
|
8
12
|
end
|
9
13
|
|
14
|
+
# Verifies the expiration claim ('exp') in the JWT token.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::ExpiredSignature] if the token has expired.
|
19
|
+
# @return [nil]
|
10
20
|
def verify!(context:, **_args)
|
11
21
|
return unless context.payload.is_a?(Hash)
|
12
22
|
return unless context.payload.key?('exp')
|
data/lib/jwt/claims/issued_at.rb
CHANGED
@@ -2,7 +2,14 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The IssuedAt class is responsible for validating the issued at claim ('iat') in a JWT token.
|
5
6
|
class IssuedAt
|
7
|
+
# Verifies the issued at claim ('iat') in the JWT token.
|
8
|
+
#
|
9
|
+
# @param context [Object] the context containing the JWT payload.
|
10
|
+
# @param _args [Hash] additional arguments (not used).
|
11
|
+
# @raise [JWT::InvalidIatError] if the issued at claim is invalid.
|
12
|
+
# @return [nil]
|
6
13
|
def verify!(context:, **_args)
|
7
14
|
return unless context.payload.is_a?(Hash)
|
8
15
|
return unless context.payload.key?('iat')
|
data/lib/jwt/claims/issuer.rb
CHANGED
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The Issuer class is responsible for validating the issuer claim ('iss') in a JWT token.
|
5
6
|
class Issuer
|
7
|
+
# Initializes a new Issuer instance.
|
8
|
+
#
|
9
|
+
# @param issuers [String, Symbol, Array<String, Symbol>] the expected issuer(s) for the JWT token.
|
6
10
|
def initialize(issuers:)
|
7
11
|
@issuers = Array(issuers).map { |item| item.is_a?(Symbol) ? item.to_s : item }
|
8
12
|
end
|
9
13
|
|
14
|
+
# Verifies the issuer claim ('iss') in the JWT token.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::InvalidIssuerError] if the issuer claim is invalid.
|
19
|
+
# @return [nil]
|
10
20
|
def verify!(context:, **_args)
|
11
21
|
case (iss = context.payload['iss'])
|
12
22
|
when *issuers
|
data/lib/jwt/claims/jwt_id.rb
CHANGED
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The JwtId class is responsible for validating the JWT ID claim ('jti') in a JWT token.
|
5
6
|
class JwtId
|
7
|
+
# Initializes a new JwtId instance.
|
8
|
+
#
|
9
|
+
# @param validator [#call] an object responding to `call` to validate the JWT ID.
|
6
10
|
def initialize(validator:)
|
7
11
|
@validator = validator
|
8
12
|
end
|
9
13
|
|
14
|
+
# Verifies the JWT ID claim ('jti') in the JWT token.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::InvalidJtiError] if the JWT ID claim is invalid or missing.
|
19
|
+
# @return [nil]
|
10
20
|
def verify!(context:, **_args)
|
11
21
|
jti = context.payload['jti']
|
12
22
|
if validator.respond_to?(:call)
|
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The NotBefore class is responsible for validating the 'nbf' (Not Before) claim in a JWT token.
|
5
6
|
class NotBefore
|
7
|
+
# Initializes a new NotBefore instance.
|
8
|
+
#
|
9
|
+
# @param leeway [Integer] the amount of leeway (in seconds) to allow when validating the 'nbf' claim. Defaults to 0.
|
6
10
|
def initialize(leeway:)
|
7
11
|
@leeway = leeway || 0
|
8
12
|
end
|
9
13
|
|
14
|
+
# Verifies the 'nbf' (Not Before) claim in the JWT token.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::ImmatureSignature] if the 'nbf' claim has not been reached.
|
19
|
+
# @return [nil]
|
10
20
|
def verify!(context:, **_args)
|
11
21
|
return unless context.payload.is_a?(Hash)
|
12
22
|
return unless context.payload.key?('nbf')
|
data/lib/jwt/claims/numeric.rb
CHANGED
@@ -2,37 +2,27 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The Numeric class is responsible for validating numeric claims in a JWT token.
|
6
|
+
# The numeric claims are: exp, iat and nbf
|
5
7
|
class Numeric
|
6
|
-
|
7
|
-
def initialize(payload)
|
8
|
-
@payload = payload
|
9
|
-
end
|
10
|
-
|
11
|
-
def verify!
|
12
|
-
JWT::Claims.verify_payload!(@payload, :numeric)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
8
|
+
# List of numeric claims that can be validated.
|
16
9
|
NUMERIC_CLAIMS = %i[
|
17
10
|
exp
|
18
11
|
iat
|
19
12
|
nbf
|
20
13
|
].freeze
|
21
14
|
|
22
|
-
|
23
|
-
return super if args.empty?
|
24
|
-
|
25
|
-
Compat.new(*args)
|
26
|
-
end
|
15
|
+
private_constant(:NUMERIC_CLAIMS)
|
27
16
|
|
17
|
+
# Verifies the numeric claims in the JWT context.
|
18
|
+
#
|
19
|
+
# @param context [Object] the context containing the JWT payload.
|
20
|
+
# @raise [JWT::InvalidClaimError] if any numeric claim is invalid.
|
21
|
+
# @return [nil]
|
28
22
|
def verify!(context:)
|
29
23
|
validate_numeric_claims(context.payload)
|
30
24
|
end
|
31
25
|
|
32
|
-
def self.verify!(payload:, **_args)
|
33
|
-
JWT::Claims.verify_payload!(payload, :numeric)
|
34
|
-
end
|
35
|
-
|
36
26
|
private
|
37
27
|
|
38
28
|
def validate_numeric_claims(payload)
|
data/lib/jwt/claims/required.rb
CHANGED
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The Required class is responsible for validating that all required claims are present in a JWT token.
|
5
6
|
class Required
|
7
|
+
# Initializes a new Required instance.
|
8
|
+
#
|
9
|
+
# @param required_claims [Array<String>] the list of required claims.
|
6
10
|
def initialize(required_claims:)
|
7
11
|
@required_claims = required_claims
|
8
12
|
end
|
9
13
|
|
14
|
+
# Verifies that all required claims are present in the JWT payload.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::MissingRequiredClaim] if any required claim is missing.
|
19
|
+
# @return [nil]
|
10
20
|
def verify!(context:, **_args)
|
11
21
|
required_claims.each do |required_claim|
|
12
22
|
next if context.payload.is_a?(Hash) && context.payload.key?(required_claim)
|
data/lib/jwt/claims/subject.rb
CHANGED
@@ -2,11 +2,21 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
+
# The Subject class is responsible for validating the subject claim ('sub') in a JWT token.
|
5
6
|
class Subject
|
7
|
+
# Initializes a new Subject instance.
|
8
|
+
#
|
9
|
+
# @param expected_subject [String] the expected subject for the JWT token.
|
6
10
|
def initialize(expected_subject:)
|
7
11
|
@expected_subject = expected_subject.to_s
|
8
12
|
end
|
9
13
|
|
14
|
+
# Verifies the subject claim ('sub') in the JWT token.
|
15
|
+
#
|
16
|
+
# @param context [Object] the context containing the JWT payload.
|
17
|
+
# @param _args [Hash] additional arguments (not used).
|
18
|
+
# @raise [JWT::InvalidSubError] if the subject claim is invalid.
|
19
|
+
# @return [nil]
|
10
20
|
def verify!(context:, **_args)
|
11
21
|
sub = context.payload['sub']
|
12
22
|
raise(JWT::InvalidSubError, "Invalid subject. Expected #{expected_subject}, received #{sub || '<none>'}") unless sub.to_s == expected_subject
|
data/lib/jwt/claims/verifier.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Claims
|
5
|
-
# @private
|
5
|
+
# @api private
|
6
6
|
module Verifier
|
7
7
|
VERIFIERS = {
|
8
8
|
exp: ->(options) { Claims::Expiration.new(leeway: options.dig(:exp, :leeway)) },
|
@@ -12,7 +12,7 @@ module JWT
|
|
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]) },
|
15
|
-
|
15
|
+
crit: ->(options) { Claims::Crit.new(expected_crits: options[:crit]) },
|
16
16
|
required: ->(options) { Claims::Required.new(required_claims: options[:required]) },
|
17
17
|
numeric: ->(*) { Claims::Numeric.new }
|
18
18
|
}.freeze
|
@@ -20,7 +20,7 @@ module JWT
|
|
20
20
|
private_constant(:VERIFIERS)
|
21
21
|
|
22
22
|
class << self
|
23
|
-
# @private
|
23
|
+
# @api private
|
24
24
|
def verify!(context, *options)
|
25
25
|
iterate_verifiers(*options) do |verifier, verifier_options|
|
26
26
|
verify_one!(context, verifier, verifier_options)
|
@@ -28,7 +28,7 @@ module JWT
|
|
28
28
|
nil
|
29
29
|
end
|
30
30
|
|
31
|
-
# @private
|
31
|
+
# @api private
|
32
32
|
def errors(context, *options)
|
33
33
|
errors = []
|
34
34
|
iterate_verifiers(*options) do |verifier, verifier_options|
|
@@ -39,7 +39,8 @@ module JWT
|
|
39
39
|
errors
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
private
|
43
|
+
|
43
44
|
def iterate_verifiers(*options)
|
44
45
|
options.each do |element|
|
45
46
|
if element.is_a?(Hash)
|
@@ -50,8 +51,6 @@ module JWT
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
|
-
private
|
54
|
-
|
55
54
|
def verify_one!(context, verifier, options)
|
56
55
|
verifier_builder = VERIFIERS.fetch(verifier) { raise ArgumentError, "#{verifier} not a valid claim verifier" }
|
57
56
|
verifier_builder.call(options || {}).verify!(context: context)
|
data/lib/jwt/claims.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'claims/audience'
|
4
|
+
require_relative 'claims/crit'
|
5
|
+
require_relative 'claims/decode_verifier'
|
4
6
|
require_relative 'claims/expiration'
|
5
7
|
require_relative 'claims/issued_at'
|
6
8
|
require_relative 'claims/issuer'
|
@@ -9,7 +11,6 @@ require_relative 'claims/not_before'
|
|
9
11
|
require_relative 'claims/numeric'
|
10
12
|
require_relative 'claims/required'
|
11
13
|
require_relative 'claims/subject'
|
12
|
-
require_relative 'claims/decode_verifier'
|
13
14
|
require_relative 'claims/verifier'
|
14
15
|
|
15
16
|
module JWT
|
@@ -26,17 +27,11 @@ module JWT
|
|
26
27
|
# sub
|
27
28
|
# required
|
28
29
|
# numeric
|
29
|
-
#
|
30
30
|
module Claims
|
31
31
|
# Represents a claim verification error
|
32
32
|
Error = Struct.new(:message, keyword_init: true)
|
33
33
|
|
34
34
|
class << self
|
35
|
-
# @deprecated Use {verify_payload!} instead. Will be removed in the next major version of ruby-jwt.
|
36
|
-
def verify!(payload, options)
|
37
|
-
DecodeVerifier.verify!(payload, options)
|
38
|
-
end
|
39
|
-
|
40
35
|
# Checks if the claims in the JWT payload are valid.
|
41
36
|
# @example
|
42
37
|
#
|
@@ -48,7 +43,7 @@ module JWT
|
|
48
43
|
# @return [void]
|
49
44
|
# @raise [JWT::DecodeError] if any claim is invalid.
|
50
45
|
def verify_payload!(payload, *options)
|
51
|
-
|
46
|
+
Verifier.verify!(VerificationContext.new(payload: payload), *options)
|
52
47
|
end
|
53
48
|
|
54
49
|
# Checks if the claims in the JWT payload are valid.
|
@@ -65,17 +60,7 @@ module JWT
|
|
65
60
|
# @param options [Array] the options for verifying the claims.
|
66
61
|
# @return [Array<JWT::Claims::Error>] the errors in the claims of the JWT
|
67
62
|
def payload_errors(payload, *options)
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
def verify_token!(token, *options)
|
74
|
-
Verifier.verify!(token, *options)
|
75
|
-
end
|
76
|
-
|
77
|
-
def token_errors(token, *options)
|
78
|
-
Verifier.errors(token, *options)
|
63
|
+
Verifier.errors(VerificationContext.new(payload: payload), *options)
|
79
64
|
end
|
80
65
|
end
|
81
66
|
end
|
@@ -5,23 +5,42 @@ require_relative 'jwk_configuration'
|
|
5
5
|
|
6
6
|
module JWT
|
7
7
|
module Configuration
|
8
|
+
# The Container class holds the configuration settings for JWT.
|
8
9
|
class Container
|
10
|
+
# @!attribute [rw] decode
|
11
|
+
# @return [DecodeConfiguration] the decode configuration.
|
12
|
+
# @!attribute [rw] jwk
|
13
|
+
# @return [JwkConfiguration] the JWK configuration.
|
14
|
+
# @!attribute [rw] strict_base64_decoding
|
15
|
+
# @return [Boolean] whether strict Base64 decoding is enabled.
|
9
16
|
attr_accessor :decode, :jwk, :strict_base64_decoding
|
17
|
+
|
18
|
+
# @!attribute [r] deprecation_warnings
|
19
|
+
# @return [Symbol] the deprecation warnings setting.
|
10
20
|
attr_reader :deprecation_warnings
|
11
21
|
|
22
|
+
# Initializes a new Container instance and resets the configuration.
|
12
23
|
def initialize
|
13
24
|
reset!
|
14
25
|
end
|
15
26
|
|
27
|
+
# Resets the configuration to default values.
|
28
|
+
#
|
29
|
+
# @return [void]
|
16
30
|
def reset!
|
17
31
|
@decode = DecodeConfiguration.new
|
18
32
|
@jwk = JwkConfiguration.new
|
19
|
-
@strict_base64_decoding = false
|
20
33
|
|
21
34
|
self.deprecation_warnings = :once
|
22
35
|
end
|
23
36
|
|
24
37
|
DEPRECATION_WARNINGS_VALUES = %i[once warn silent].freeze
|
38
|
+
private_constant(:DEPRECATION_WARNINGS_VALUES)
|
39
|
+
# Sets the deprecation warnings setting.
|
40
|
+
#
|
41
|
+
# @param value [Symbol] the deprecation warnings setting. Must be one of `:once`, `:warn`, or `:silent`.
|
42
|
+
# @raise [ArgumentError] if the value is not one of the supported values.
|
43
|
+
# @return [void]
|
25
44
|
def deprecation_warnings=(value)
|
26
45
|
raise ArgumentError, "Invalid deprecation_warnings value #{value}. Supported values: #{DEPRECATION_WARNINGS_VALUES}" unless DEPRECATION_WARNINGS_VALUES.include?(value)
|
27
46
|
|
@@ -2,7 +2,29 @@
|
|
2
2
|
|
3
3
|
module JWT
|
4
4
|
module Configuration
|
5
|
+
# The DecodeConfiguration class holds the configuration settings for decoding JWT tokens.
|
5
6
|
class DecodeConfiguration
|
7
|
+
# @!attribute [rw] verify_expiration
|
8
|
+
# @return [Boolean] whether to verify the expiration claim.
|
9
|
+
# @!attribute [rw] verify_not_before
|
10
|
+
# @return [Boolean] whether to verify the not before claim.
|
11
|
+
# @!attribute [rw] verify_iss
|
12
|
+
# @return [Boolean] whether to verify the issuer claim.
|
13
|
+
# @!attribute [rw] verify_iat
|
14
|
+
# @return [Boolean] whether to verify the issued at claim.
|
15
|
+
# @!attribute [rw] verify_jti
|
16
|
+
# @return [Boolean] whether to verify the JWT ID claim.
|
17
|
+
# @!attribute [rw] verify_aud
|
18
|
+
# @return [Boolean] whether to verify the audience claim.
|
19
|
+
# @!attribute [rw] verify_sub
|
20
|
+
# @return [Boolean] whether to verify the subject claim.
|
21
|
+
# @!attribute [rw] leeway
|
22
|
+
# @return [Integer] the leeway in seconds for time-based claims.
|
23
|
+
# @!attribute [rw] algorithms
|
24
|
+
# @return [Array<String>] the list of acceptable algorithms.
|
25
|
+
# @!attribute [rw] required_claims
|
26
|
+
# @return [Array<String>] the list of required claims.
|
27
|
+
|
6
28
|
attr_accessor :verify_expiration,
|
7
29
|
:verify_not_before,
|
8
30
|
:verify_iss,
|
@@ -14,6 +36,7 @@ module JWT
|
|
14
36
|
:algorithms,
|
15
37
|
:required_claims
|
16
38
|
|
39
|
+
# Initializes a new DecodeConfiguration instance with default settings.
|
17
40
|
def initialize
|
18
41
|
@verify_expiration = true
|
19
42
|
@verify_not_before = true
|
@@ -27,6 +50,7 @@ module JWT
|
|
27
50
|
@required_claims = []
|
28
51
|
end
|
29
52
|
|
53
|
+
# @api private
|
30
54
|
def to_h
|
31
55
|
{
|
32
56
|
verify_expiration: verify_expiration,
|
data/lib/jwt/configuration.rb
CHANGED
@@ -3,11 +3,19 @@
|
|
3
3
|
require_relative 'configuration/container'
|
4
4
|
|
5
5
|
module JWT
|
6
|
+
# The Configuration module provides methods to configure JWT settings.
|
6
7
|
module Configuration
|
8
|
+
# Configures the JWT settings.
|
9
|
+
#
|
10
|
+
# @yield [config] Gives the current configuration to the block.
|
11
|
+
# @yieldparam config [JWT::Configuration::Container] the configuration container.
|
7
12
|
def configure
|
8
13
|
yield(configuration)
|
9
14
|
end
|
10
15
|
|
16
|
+
# Returns the JWT configuration container.
|
17
|
+
#
|
18
|
+
# @return [JWT::Configuration::Container] the configuration container.
|
11
19
|
def configuration
|
12
20
|
@configuration ||= ::JWT::Configuration::Container.new
|
13
21
|
end
|