jwt 2.7.1 → 2.10.3

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +157 -27
  3. data/README.md +207 -101
  4. data/lib/jwt/base64.rb +19 -2
  5. data/lib/jwt/claims/audience.rb +30 -0
  6. data/lib/jwt/claims/crit.rb +35 -0
  7. data/lib/jwt/claims/decode_verifier.rb +40 -0
  8. data/lib/jwt/claims/expiration.rb +32 -0
  9. data/lib/jwt/claims/issued_at.rb +22 -0
  10. data/lib/jwt/claims/issuer.rb +34 -0
  11. data/lib/jwt/claims/jwt_id.rb +35 -0
  12. data/lib/jwt/claims/not_before.rb +32 -0
  13. data/lib/jwt/claims/numeric.rb +77 -0
  14. data/lib/jwt/claims/required.rb +33 -0
  15. data/lib/jwt/claims/subject.rb +30 -0
  16. data/lib/jwt/claims/verification_methods.rb +20 -0
  17. data/lib/jwt/claims/verifier.rb +61 -0
  18. data/lib/jwt/claims.rb +74 -0
  19. data/lib/jwt/claims_validator.rb +6 -25
  20. data/lib/jwt/configuration/container.rb +34 -3
  21. data/lib/jwt/configuration/decode_configuration.rb +24 -0
  22. data/lib/jwt/configuration/jwk_configuration.rb +2 -1
  23. data/lib/jwt/configuration.rb +8 -0
  24. data/lib/jwt/decode.rb +34 -82
  25. data/lib/jwt/deprecations.rb +49 -0
  26. data/lib/jwt/encode.rb +18 -67
  27. data/lib/jwt/encoded_token.rb +139 -0
  28. data/lib/jwt/error.rb +35 -0
  29. data/lib/jwt/json.rb +1 -1
  30. data/lib/jwt/jwa/compat.rb +32 -0
  31. data/lib/jwt/{algos → jwa}/ecdsa.rb +40 -26
  32. data/lib/jwt/jwa/eddsa.rb +35 -0
  33. data/lib/jwt/{algos → jwa}/hmac.rb +31 -20
  34. data/lib/jwt/jwa/hmac_rbnacl.rb +50 -0
  35. data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +47 -0
  36. data/lib/jwt/jwa/none.rb +24 -0
  37. data/lib/jwt/jwa/ps.rb +35 -0
  38. data/lib/jwt/jwa/rsa.rb +35 -0
  39. data/lib/jwt/jwa/signing_algorithm.rb +63 -0
  40. data/lib/jwt/jwa/unsupported.rb +20 -0
  41. data/lib/jwt/jwa/wrapper.rb +44 -0
  42. data/lib/jwt/jwa.rb +58 -0
  43. data/lib/jwt/jwk/ec.rb +44 -30
  44. data/lib/jwt/jwk/hmac.rb +2 -3
  45. data/lib/jwt/jwk/key_base.rb +4 -1
  46. data/lib/jwt/jwk/key_finder.rb +5 -4
  47. data/lib/jwt/jwk/kid_as_key_digest.rb +1 -0
  48. data/lib/jwt/jwk/okp_rbnacl.rb +3 -4
  49. data/lib/jwt/jwk/rsa.rb +2 -3
  50. data/lib/jwt/jwk/set.rb +3 -1
  51. data/lib/jwt/jwk.rb +2 -1
  52. data/lib/jwt/token.rb +112 -0
  53. data/lib/jwt/verify.rb +16 -89
  54. data/lib/jwt/version.rb +33 -11
  55. data/lib/jwt/x5c_key_finder.rb +2 -5
  56. data/lib/jwt.rb +24 -1
  57. data/ruby-jwt.gemspec +4 -0
  58. metadata +76 -18
  59. data/lib/jwt/algos/algo_wrapper.rb +0 -26
  60. data/lib/jwt/algos/eddsa.rb +0 -33
  61. data/lib/jwt/algos/hmac_rbnacl.rb +0 -53
  62. data/lib/jwt/algos/hmac_rbnacl_fixed.rb +0 -52
  63. data/lib/jwt/algos/none.rb +0 -19
  64. data/lib/jwt/algos/ps.rb +0 -41
  65. data/lib/jwt/algos/rsa.rb +0 -23
  66. data/lib/jwt/algos/unsupported.rb +0 -19
  67. data/lib/jwt/algos.rb +0 -66
@@ -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,
@@ -5,6 +5,7 @@ require_relative '../jwk/thumbprint'
5
5
 
6
6
  module JWT
7
7
  module Configuration
8
+ # @api private
8
9
  class JwkConfiguration
9
10
  def initialize
10
11
  self.kid_generator_type = :key_digest
@@ -18,7 +19,7 @@ module JWT
18
19
  JWT::JWK::Thumbprint
19
20
  else
20
21
  raise ArgumentError, "#{value} is not a valid kid generator type."
21
- end
22
+ end
22
23
  end
23
24
 
24
25
  attr_accessor :kid_generator
@@ -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
data/lib/jwt/decode.rb CHANGED
@@ -1,72 +1,69 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
-
5
- require 'jwt/verify'
6
4
  require 'jwt/x5c_key_finder'
7
5
 
8
- # JWT::Decode module
9
6
  module JWT
10
- # Decoding logic for JWT
7
+ # The Decode class is responsible for decoding and verifying JWT tokens.
11
8
  class Decode
9
+ # Initializes a new Decode instance.
10
+ #
11
+ # @param jwt [String] the JWT to decode.
12
+ # @param key [String, Array<String>] the key(s) to use for verification.
13
+ # @param verify [Boolean] whether to verify the token's signature.
14
+ # @param options [Hash] additional options for decoding and verification.
15
+ # @param keyfinder [Proc] an optional key finder block to dynamically find the key for verification.
16
+ # @raise [JWT::DecodeError] if decoding or verification fails.
12
17
  def initialize(jwt, key, verify, options, &keyfinder)
13
- raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
18
+ raise JWT::DecodeError, 'Nil JSON web token' unless jwt
14
19
 
15
- @jwt = jwt
20
+ @token = EncodedToken.new(jwt)
16
21
  @key = key
17
22
  @options = options
18
- @segments = jwt.split('.')
19
23
  @verify = verify
20
- @signature = ''
21
24
  @keyfinder = keyfinder
22
25
  end
23
26
 
27
+ # Decodes the JWT token and verifies its segments if verification is enabled.
28
+ #
29
+ # @return [Array<Hash>] an array containing the decoded payload and header.
24
30
  def decode_segments
25
31
  validate_segment_count!
26
32
  if @verify
27
- decode_signature
28
33
  verify_algo
29
34
  set_key
30
35
  verify_signature
31
- verify_claims
36
+ Claims::DecodeVerifier.verify!(token.payload, @options)
32
37
  end
33
- raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload
34
38
 
35
- [payload, header]
39
+ [token.payload, token.header]
36
40
  end
37
41
 
38
42
  private
39
43
 
40
- def verify_signature
41
- return unless @key || @verify
44
+ attr_reader :token
42
45
 
46
+ def verify_signature
43
47
  return if none_algorithm?
44
48
 
45
49
  raise JWT::DecodeError, 'No verification key available' unless @key
46
50
 
47
- return if Array(@key).any? { |key| verify_signature_for?(key) }
48
-
49
- raise(JWT::VerificationError, 'Signature verification failed')
51
+ token.verify_signature!(algorithm: allowed_and_valid_algorithms, key: @key)
50
52
  end
51
53
 
52
54
  def verify_algo
53
- raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms.empty?
54
- raise(JWT::IncorrectAlgorithm, 'Token is missing alg header') unless alg_in_header
55
- raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') if allowed_and_valid_algorithms.empty?
55
+ raise JWT::IncorrectAlgorithm, 'An algorithm must be specified' if allowed_algorithms.empty?
56
+ raise JWT::DecodeError, 'Token header not a JSON object' unless token.header.is_a?(Hash)
57
+ raise JWT::IncorrectAlgorithm, 'Token is missing alg header' unless alg_in_header
58
+ raise JWT::IncorrectAlgorithm, 'Expected a different algorithm' if allowed_and_valid_algorithms.empty?
56
59
  end
57
60
 
58
61
  def set_key
59
62
  @key = find_key(&@keyfinder) if @keyfinder
60
- @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks], allow_nil_kid: @options[:allow_nil_kid]).key_for(header['kid']) if @options[:jwks]
61
- if (x5c_options = @options[:x5c])
62
- @key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(header['x5c'])
63
- end
64
- end
63
+ @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks], allow_nil_kid: @options[:allow_nil_kid]).key_for(token.header['kid']) if @options[:jwks]
64
+ return unless (x5c_options = @options[:x5c])
65
65
 
66
- def verify_signature_for?(key)
67
- allowed_and_valid_algorithms.any? do |alg|
68
- alg.verify(data: signing_input, signature: @signature, verification_key: key)
69
- end
66
+ @key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(token.header['x5c'])
70
67
  end
71
68
 
72
69
  def allowed_and_valid_algorithms
@@ -92,77 +89,32 @@ module JWT
92
89
  end
93
90
 
94
91
  def resolve_allowed_algorithms
95
- algs = given_algorithms.map do |alg|
96
- if Algos.implementation?(alg)
97
- alg
98
- else
99
- Algos.create(alg)
100
- end
101
- end
102
-
103
- sort_by_alg_header(algs)
104
- end
105
-
106
- # Move algorithms matching the JWT alg header to the beginning of the list
107
- def sort_by_alg_header(algs)
108
- return algs if algs.size <= 1
109
-
110
- algs.partition { |alg| alg.valid_alg?(alg_in_header) }.flatten
92
+ given_algorithms.map { |alg| JWA.resolve(alg) }
111
93
  end
112
94
 
113
95
  def find_key(&keyfinder)
114
- key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header))
96
+ key = (keyfinder.arity == 2 ? yield(token.header, token.payload) : yield(token.header))
115
97
  # key can be of type [string, nil, OpenSSL::PKey, Array]
116
98
  return key if key && !Array(key).empty?
117
99
 
118
100
  raise JWT::DecodeError, 'No verification key available'
119
101
  end
120
102
 
121
- def verify_claims
122
- Verify.verify_claims(payload, @options)
123
- Verify.verify_required_claims(payload, @options)
124
- end
125
-
126
103
  def validate_segment_count!
127
- return if segment_length == 3
128
- return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed
129
- return if segment_length == 2 && none_algorithm?
130
-
131
- raise(JWT::DecodeError, 'Not enough or too many segments')
132
- end
104
+ segment_count = token.jwt.count('.') + 1
105
+ return if segment_count == 3
106
+ return if !@verify && segment_count == 2 # If no verifying required, the signature is not needed
107
+ return if segment_count == 2 && none_algorithm?
133
108
 
134
- def segment_length
135
- @segments.count
109
+ raise JWT::DecodeError, 'Not enough or too many segments'
136
110
  end
137
111
 
138
112
  def none_algorithm?
139
113
  alg_in_header == 'none'
140
114
  end
141
115
 
142
- def decode_signature
143
- @signature = ::JWT::Base64.url_decode(@segments[2] || '')
144
- end
145
-
146
116
  def alg_in_header
147
- header['alg']
148
- end
149
-
150
- def header
151
- @header ||= parse_and_decode @segments[0]
152
- end
153
-
154
- def payload
155
- @payload ||= parse_and_decode @segments[1]
156
- end
157
-
158
- def signing_input
159
- @segments.first(2).join('.')
160
- end
161
-
162
- def parse_and_decode(segment)
163
- JWT::JSON.parse(::JWT::Base64.url_decode(segment))
164
- rescue ::JSON::ParserError
165
- raise JWT::DecodeError, 'Invalid segment encoding'
117
+ token.header['alg']
166
118
  end
167
119
  end
168
120
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ # Deprecations module to handle deprecation warnings in the gem
5
+ # @api private
6
+ module Deprecations
7
+ class << self
8
+ def context
9
+ yield.tap { emit_warnings }
10
+ ensure
11
+ Thread.current[:jwt_warning_store] = nil
12
+ end
13
+
14
+ def warning(message, only_if_valid: false)
15
+ method_name = only_if_valid ? :store : :warn
16
+ case JWT.configuration.deprecation_warnings
17
+ when :once
18
+ return if record_warned(message)
19
+ when :warn
20
+ # noop
21
+ else
22
+ return
23
+ end
24
+
25
+ send(method_name, "[DEPRECATION WARNING] #{message}")
26
+ end
27
+
28
+ def store(message)
29
+ (Thread.current[:jwt_warning_store] ||= []) << message
30
+ end
31
+
32
+ def emit_warnings
33
+ return if Thread.current[:jwt_warning_store].nil?
34
+
35
+ Thread.current[:jwt_warning_store].each { |warning| warn(warning) }
36
+ end
37
+
38
+ private
39
+
40
+ def record_warned(message)
41
+ @warned ||= []
42
+ return true if @warned.include?(message)
43
+
44
+ @warned << message
45
+ false
46
+ end
47
+ end
48
+ end
49
+ end
data/lib/jwt/encode.rb CHANGED
@@ -1,79 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'algos'
4
- require_relative 'claims_validator'
3
+ require_relative 'jwa'
5
4
 
6
- # JWT::Encode module
7
5
  module JWT
8
- # Encoding logic for JWT
6
+ # The Encode class is responsible for encoding JWT tokens.
9
7
  class Encode
10
- ALG_KEY = 'alg'
11
-
8
+ # Initializes a new Encode instance.
9
+ #
10
+ # @param options [Hash] the options for encoding the JWT token.
11
+ # @option options [Hash] :payload the payload of the JWT token.
12
+ # @option options [Hash] :headers the headers of the JWT token.
13
+ # @option options [String] :key the key used to sign the JWT token.
14
+ # @option options [String] :algorithm the algorithm used to sign the JWT token.
12
15
  def initialize(options)
13
- @payload = options[:payload]
14
- @key = options[:key]
15
- @algorithm = resolve_algorithm(options[:algorithm])
16
- @headers = options[:headers].transform_keys(&:to_s)
17
- @headers[ALG_KEY] = @algorithm.alg
16
+ @token = Token.new(payload: options[:payload], header: options[:headers])
17
+ @key = options[:key]
18
+ @algorithm = options[:algorithm]
18
19
  end
19
20
 
21
+ # Encodes the JWT token and returns its segments.
22
+ #
23
+ # @return [String] the encoded JWT token.
20
24
  def segments
21
- validate_claims!
22
- combine(encoded_header_and_payload, encoded_signature)
23
- end
24
-
25
- private
26
-
27
- def resolve_algorithm(algorithm)
28
- return algorithm if Algos.implementation?(algorithm)
29
-
30
- Algos.create(algorithm)
31
- end
32
-
33
- def encoded_header
34
- @encoded_header ||= encode_header
35
- end
36
-
37
- def encoded_payload
38
- @encoded_payload ||= encode_payload
39
- end
40
-
41
- def encoded_signature
42
- @encoded_signature ||= encode_signature
43
- end
44
-
45
- def encoded_header_and_payload
46
- @encoded_header_and_payload ||= combine(encoded_header, encoded_payload)
47
- end
48
-
49
- def encode_header
50
- encode_data(@headers)
51
- end
52
-
53
- def encode_payload
54
- encode_data(@payload)
55
- end
56
-
57
- def signature
58
- @algorithm.sign(data: encoded_header_and_payload, signing_key: @key)
59
- end
60
-
61
- def validate_claims!
62
- return unless @payload.is_a?(Hash)
63
-
64
- ClaimsValidator.new(@payload).validate!
65
- end
66
-
67
- def encode_signature
68
- ::JWT::Base64.url_encode(signature)
69
- end
70
-
71
- def encode_data(data)
72
- ::JWT::Base64.url_encode(JWT::JSON.generate(data))
73
- end
74
-
75
- def combine(*parts)
76
- parts.join('.')
25
+ @token.verify_claims!(:numeric)
26
+ @token.sign!(algorithm: @algorithm, key: @key)
27
+ @token.jwt
77
28
  end
78
29
  end
79
30
  end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ # Represents an encoded JWT token
5
+ #
6
+ # Processing an encoded and signed token:
7
+ #
8
+ # token = JWT::Token.new(payload: {pay: 'load'})
9
+ # token.sign!(algorithm: 'HS256', key: 'secret')
10
+ #
11
+ # encoded_token = JWT::EncodedToken.new(token.jwt)
12
+ # encoded_token.verify_signature!(algorithm: 'HS256', key: 'secret')
13
+ # encoded_token.payload # => {'pay' => 'load'}
14
+ class EncodedToken
15
+ include Claims::VerificationMethods
16
+
17
+ # Returns the original token provided to the class.
18
+ # @return [String] The JWT token.
19
+ attr_reader :jwt
20
+
21
+ # Initializes a new EncodedToken instance.
22
+ #
23
+ # @param jwt [String] the encoded JWT token.
24
+ # @raise [ArgumentError] if the provided JWT is not a String.
25
+ def initialize(jwt)
26
+ raise ArgumentError, 'Provided JWT must be a String' unless jwt.is_a?(String)
27
+
28
+ @jwt = jwt
29
+ @encoded_header, @encoded_payload, @encoded_signature = jwt.split('.')
30
+ end
31
+
32
+ # Returns the decoded signature of the JWT token.
33
+ #
34
+ # @return [String] the decoded signature.
35
+ def signature
36
+ @signature ||= ::JWT::Base64.url_decode(encoded_signature || '')
37
+ end
38
+
39
+ # Returns the encoded signature of the JWT token.
40
+ #
41
+ # @return [String] the encoded signature.
42
+ attr_reader :encoded_signature
43
+
44
+ # Returns the decoded header of the JWT token.
45
+ #
46
+ # @return [Hash] the header.
47
+ def header
48
+ @header ||= parse_and_decode(@encoded_header)
49
+ end
50
+
51
+ # Returns the encoded header of the JWT token.
52
+ #
53
+ # @return [String] the encoded header.
54
+ attr_reader :encoded_header
55
+
56
+ # Returns the payload of the JWT token.
57
+ #
58
+ # @return [Hash] the payload.
59
+ def payload
60
+ @payload ||= decode_payload
61
+ end
62
+
63
+ # Sets or returns the encoded payload of the JWT token.
64
+ #
65
+ # @return [String] the encoded payload.
66
+ attr_accessor :encoded_payload
67
+
68
+ # Returns the signing input of the JWT token.
69
+ #
70
+ # @return [String] the signing input.
71
+ def signing_input
72
+ [encoded_header, encoded_payload].join('.')
73
+ end
74
+
75
+ # Verifies the signature of the JWT token.
76
+ #
77
+ # @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.
78
+ # @param key [String, Array<String>] the key(s) to use for verification.
79
+ # @param key_finder [#call] an object responding to `call` to find the key for verification.
80
+ # @return [nil]
81
+ # @raise [JWT::VerificationError] if the signature verification fails.
82
+ # @raise [ArgumentError] if neither key nor key_finder is provided, or if both are provided.
83
+ def verify_signature!(algorithm:, key: nil, key_finder: nil)
84
+ raise ArgumentError, 'Provide either key or key_finder, not both or neither' if key.nil? == key_finder.nil?
85
+
86
+ key ||= key_finder.call(self)
87
+
88
+ return if valid_signature?(algorithm: algorithm, key: key)
89
+
90
+ raise JWT::VerificationError, 'Signature verification failed'
91
+ end
92
+
93
+ # Checks if the signature of the JWT token is valid.
94
+ #
95
+ # @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.
96
+ # @param key [String, Array<String>] the key(s) to use for verification.
97
+ # @return [Boolean] true if the signature is valid, false otherwise.
98
+ def valid_signature?(algorithm:, key:)
99
+ Array(JWA.resolve_and_sort(algorithms: algorithm, preferred_algorithm: header['alg'])).any? do |algo|
100
+ Array(key).any? do |one_key|
101
+ algo.verify(data: signing_input, signature: signature, verification_key: one_key)
102
+ end
103
+ end
104
+ end
105
+
106
+ alias to_s jwt
107
+
108
+ private
109
+
110
+ def decode_payload
111
+ raise JWT::DecodeError, 'Encoded payload is empty' if encoded_payload == ''
112
+
113
+ if unencoded_payload?
114
+ verify_claims!(crit: ['b64'])
115
+ return parse_unencoded(encoded_payload)
116
+ end
117
+
118
+ parse_and_decode(encoded_payload)
119
+ end
120
+
121
+ def unencoded_payload?
122
+ header['b64'] == false
123
+ end
124
+
125
+ def parse_and_decode(segment)
126
+ parse(::JWT::Base64.url_decode(segment || ''))
127
+ end
128
+
129
+ def parse_unencoded(segment)
130
+ parse(segment)
131
+ end
132
+
133
+ def parse(segment)
134
+ JWT::JSON.parse(segment)
135
+ rescue ::JSON::ParserError
136
+ raise JWT::DecodeError, 'Invalid segment encoding'
137
+ end
138
+ end
139
+ end
data/lib/jwt/error.rb CHANGED
@@ -1,22 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
+ # The EncodeError class is raised when there is an error encoding a JWT.
4
5
  class EncodeError < StandardError; end
6
+
7
+ # The DecodeError class is raised when there is an error decoding a JWT.
5
8
  class DecodeError < StandardError; end
9
+
10
+ # The RequiredDependencyError class is raised when a required dependency is missing.
6
11
  class RequiredDependencyError < StandardError; end
7
12
 
13
+ # The VerificationError class is raised when there is an error verifying a JWT.
8
14
  class VerificationError < DecodeError; end
15
+
16
+ # The ExpiredSignature class is raised when the JWT signature has expired.
9
17
  class ExpiredSignature < DecodeError; end
18
+
19
+ # The IncorrectAlgorithm class is raised when the JWT algorithm is incorrect.
10
20
  class IncorrectAlgorithm < DecodeError; end
21
+
22
+ # The ImmatureSignature class is raised when the JWT signature is immature.
11
23
  class ImmatureSignature < DecodeError; end
24
+
25
+ # The InvalidIssuerError class is raised when the JWT issuer is invalid.
12
26
  class InvalidIssuerError < DecodeError; end
27
+
28
+ # The UnsupportedEcdsaCurve class is raised when the ECDSA curve is unsupported.
13
29
  class UnsupportedEcdsaCurve < IncorrectAlgorithm; end
30
+
31
+ # The InvalidIatError class is raised when the JWT issued at (iat) claim is invalid.
14
32
  class InvalidIatError < DecodeError; end
33
+
34
+ # The InvalidAudError class is raised when the JWT audience (aud) claim is invalid.
15
35
  class InvalidAudError < DecodeError; end
36
+
37
+ # The InvalidSubError class is raised when the JWT subject (sub) claim is invalid.
16
38
  class InvalidSubError < DecodeError; end
39
+
40
+ # The InvalidCritError class is raised when the JWT crit header is invalid.
41
+ class InvalidCritError < DecodeError; end
42
+
43
+ # The InvalidJtiError class is raised when the JWT ID (jti) claim is invalid.
17
44
  class InvalidJtiError < DecodeError; end
45
+
46
+ # The InvalidPayload class is raised when the JWT payload is invalid.
18
47
  class InvalidPayload < DecodeError; end
48
+
49
+ # The MissingRequiredClaim class is raised when a required claim is missing from the JWT.
19
50
  class MissingRequiredClaim < DecodeError; end
20
51
 
52
+ # The Base64DecodeError class is raised when there is an error decoding a Base64-encoded string.
53
+ class Base64DecodeError < DecodeError; end
54
+
55
+ # The JWKError class is raised when there is an error with the JSON Web Key (JWK).
21
56
  class JWKError < DecodeError; end
22
57
  end
data/lib/jwt/json.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require 'json'
4
4
 
5
5
  module JWT
6
- # JSON wrapper
6
+ # @api private
7
7
  class JSON
8
8
  class << self
9
9
  def generate(data)
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ module JWA
5
+ # Provides backwards compatibility for algorithms
6
+ # @api private
7
+ module Compat
8
+ # @api private
9
+ module ClassMethods
10
+ def from_algorithm(algorithm)
11
+ new(algorithm)
12
+ end
13
+
14
+ def sign(algorithm, msg, key)
15
+ Deprecations.warning('Support for calling sign with positional arguments will be removed in future ruby-jwt versions')
16
+
17
+ from_algorithm(algorithm).sign(data: msg, signing_key: key)
18
+ end
19
+
20
+ def verify(algorithm, key, signing_input, signature)
21
+ Deprecations.warning('Support for calling verify with positional arguments will be removed in future ruby-jwt versions')
22
+
23
+ from_algorithm(algorithm).verify(data: signing_input, signature: signature, verification_key: key)
24
+ end
25
+ end
26
+
27
+ def self.included(klass)
28
+ klass.extend(ClassMethods)
29
+ end
30
+ end
31
+ end
32
+ end