jwt 2.3.0 → 2.4.1

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.
data/README.md CHANGED
@@ -12,10 +12,12 @@ A ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools
12
12
  If you have further questions related to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
13
13
 
14
14
  ## Announcements
15
-
15
+ * Ruby 2.4 support is going to be dropped in version 2.4.0
16
16
  * Ruby 1.9.3 support was dropped at December 31st, 2016.
17
17
  * Version 1.5.3 yanked. See: [#132](https://github.com/jwt/ruby-jwt/issues/132) and [#133](https://github.com/jwt/ruby-jwt/issues/133)
18
18
 
19
+ See [CHANGELOG.md](CHANGELOG.md) for a complete set of changes.
20
+
19
21
  ## Sponsors
20
22
 
21
23
  |Logo|Message|
@@ -42,7 +44,7 @@ The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cr
42
44
 
43
45
  See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)
44
46
 
45
- **NONE**
47
+ ### **NONE**
46
48
 
47
49
  * none - unsigned token
48
50
 
@@ -68,7 +70,7 @@ decoded_token = JWT.decode token, nil, false
68
70
  puts decoded_token
69
71
  ```
70
72
 
71
- **HMAC**
73
+ ### **HMAC**
72
74
 
73
75
  * HS256 - HMAC using SHA-256 hash algorithm
74
76
  * HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below)
@@ -100,7 +102,7 @@ Note: If [RbNaCl](https://github.com/cryptosphere/rbnacl) is loadable, ruby-jwt
100
102
  [libsodium](https://github.com/jedisct1/libsodium), it can be installed
101
103
  on MacOS with `brew install libsodium`.
102
104
 
103
- **RSA**
105
+ ### **RSA**
104
106
 
105
107
  * RS256 - RSA using SHA-256 hash algorithm
106
108
  * RS384 - RSA using SHA-384 hash algorithm
@@ -125,11 +127,12 @@ decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'RS256' }
125
127
  puts decoded_token
126
128
  ```
127
129
 
128
- **ECDSA**
130
+ ### **ECDSA**
129
131
 
130
132
  * ES256 - ECDSA using P-256 and SHA-256
131
133
  * ES384 - ECDSA using P-384 and SHA-384
132
134
  * ES512 - ECDSA using P-521 and SHA-512
135
+ * ES256K - ECDSA using P-256K and SHA-256
133
136
 
134
137
  ```ruby
135
138
  ecdsa_key = OpenSSL::PKey::EC.new 'prime256v1'
@@ -152,7 +155,7 @@ decoded_token = JWT.decode token, ecdsa_public, true, { algorithm: 'ES256' }
152
155
  puts decoded_token
153
156
  ```
154
157
 
155
- **EDDSA**
158
+ ### **EDDSA**
156
159
 
157
160
  In order to use this algorithm you need to add the `RbNaCl` gem to you `Gemfile`.
158
161
 
@@ -181,7 +184,7 @@ decoded_token = JWT.decode token, public_key, true, { algorithm: 'ED25519' }
181
184
 
182
185
  ```
183
186
 
184
- **RSASSA-PSS**
187
+ ### **RSASSA-PSS**
185
188
 
186
189
  In order to use this algorithm you need to add the `openssl` gem to you `Gemfile` with a version greater or equal to `2.1`.
187
190
 
@@ -370,6 +373,36 @@ rescue JWT::InvalidIssuerError
370
373
  end
371
374
  ```
372
375
 
376
+ You can also pass a Regexp or Proc (with arity 1), verification will pass if the regexp matches or the proc returns truthy.
377
+ On supported ruby versions (>= 2.5) you can also delegate to methods, on older versions you will have
378
+ to convert them to proc (using `to_proc`)
379
+
380
+ ```ruby
381
+ JWT.decode token, hmac_secret, true,
382
+ iss: %r'https://my.awesome.website/',
383
+ verify_iss: true,
384
+ algorithm: 'HS256'
385
+ ```
386
+
387
+ ```ruby
388
+ JWT.decode token, hmac_secret, true,
389
+ iss: ->(issuer) { issuer.start_with?('My Awesome Company Inc') },
390
+ verify_iss: true,
391
+ algorithm: 'HS256'
392
+ ```
393
+
394
+ ```ruby
395
+ JWT.decode token, hmac_secret, true,
396
+ iss: method(:valid_issuer?),
397
+ verify_iss: true,
398
+ algorithm: 'HS256'
399
+
400
+ # somewhere in the same class:
401
+ def valid_issuer?(issuer)
402
+ # custom validation
403
+ end
404
+ ```
405
+
373
406
  ### Audience Claim
374
407
 
375
408
  From [Oauth JSON Web Token 4.1.3. "aud" (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3):
@@ -486,13 +519,34 @@ end
486
519
 
487
520
  You can specify claims that must be present for decoding to be successful. JWT::MissingRequiredClaim will be raised if any are missing
488
521
  ```ruby
489
- # Will raise a JWT::ExpiredSignature error if the 'exp' claim is absent
522
+ # Will raise a JWT::MissingRequiredClaim error if the 'exp' claim is absent
490
523
  JWT.decode token, hmac_secret, true, { required_claims: ['exp'], algorithm: 'HS256' }
491
524
  ```
492
525
 
526
+ ### X.509 certificates in x5c header
527
+
528
+ A JWT signature can be verified using certificate(s) given in the `x5c` header. Before doing that, the trustworthiness of these certificate(s) must be established. This is done in accordance with RFC 5280 which (among other things) verifies the certificate(s) are issued by a trusted root certificate, the timestamps are valid, and none of the certificate(s) are revoked (i.e. being present in the root certificate's Certificate Revocation List).
529
+
530
+ ```ruby
531
+ root_certificates = [] # trusted `OpenSSL::X509::Certificate` objects
532
+ crl_uris = root_certificates.map(&:crl_uris)
533
+ crls = crl_uris.map do |uri|
534
+ # look up cached CRL by `uri` and return it if found, otherwise continue
535
+ crl = Net::HTTP.get(uri)
536
+ crl = OpenSSL::X509::CRL.new(crl)
537
+ # cache `crl` using `uri` as the key, expiry set to `crl.next_update` timestamp
538
+ end
539
+
540
+ begin
541
+ JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls })
542
+ rescue JWT::DecodeError
543
+ # Handle error, e.g. x5c header certificate revoked or expired
544
+ end
545
+ ```
546
+
493
547
  ### JSON Web Key (JWK)
494
548
 
495
- JWK is a JSON structure representing a cryptographic key. Currently only supports RSA public keys.
549
+ JWK is a JSON structure representing a cryptographic key. Currently only supports RSA, EC and HMAC keys.
496
550
 
497
551
  ```ruby
498
552
  jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), "optional-kid")
@@ -524,7 +578,7 @@ JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwks})
524
578
 
525
579
  ### Importing and exporting JSON Web Keys
526
580
 
527
- The ::JWT::JWK class can be used to import and export both the public key (default behaviour) and the private key. To include the private key in the export pass the `include_private` parameter to the export method.
581
+ The ::JWT::JWK class can be used to import and export both the public key (default behaviour) and the private key. To include the private key in the export pass the `include_private` parameter to the export method.
528
582
 
529
583
  ```ruby
530
584
  jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048))
@@ -533,27 +587,14 @@ jwk_hash = jwk.export
533
587
  jwk_hash_with_private_key = jwk.export(include_private: true)
534
588
  ```
535
589
 
536
- # Development and Tests
537
-
538
- We depend on [Bundler](http://rubygems.org/gems/bundler) for defining gemspec and performing releases to rubygems.org, which can be done with
539
-
540
- ```bash
541
- rake release
542
- ```
543
-
544
- The tests are written with rspec. [Appraisal](https://github.com/thoughtbot/appraisal) is used to ensure compatibility with 3rd party dependencies providing cryptographic features.
545
-
546
- ```bash
547
- bundle install
548
- bundle exec appraisal rake test
549
- ```
590
+ ## How to contribute
550
591
 
551
- **If you want a release cut with your PR, please include a version bump according to [Semantic Versioning](http://semver.org/)**
592
+ See [CONTRIBUTING](CONTRIBUTING.md).
552
593
 
553
594
  ## Contributors
554
595
 
555
- See `AUTHORS` file.
596
+ See [AUTHORS](AUTHORS).
556
597
 
557
598
  ## License
558
599
 
559
- See `LICENSE` file.
600
+ See [LICENSE](LICENSE).
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'bundler/gem_tasks'
3
5
 
@@ -1,35 +1,64 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Ecdsa
4
6
  module_function
5
7
 
6
- SUPPORTED = %w[ES256 ES384 ES512].freeze
7
8
  NAMED_CURVES = {
8
- 'prime256v1' => 'ES256',
9
- 'secp384r1' => 'ES384',
10
- 'secp521r1' => 'ES512'
9
+ 'prime256v1' => {
10
+ algorithm: 'ES256',
11
+ digest: 'sha256'
12
+ },
13
+ 'secp256r1' => { # alias for prime256v1
14
+ algorithm: 'ES256',
15
+ digest: 'sha256'
16
+ },
17
+ 'secp384r1' => {
18
+ algorithm: 'ES384',
19
+ digest: 'sha384'
20
+ },
21
+ 'secp521r1' => {
22
+ algorithm: 'ES512',
23
+ digest: 'sha512'
24
+ },
25
+ 'secp256k1' => {
26
+ algorithm: 'ES256K',
27
+ digest: 'sha256'
28
+ }
11
29
  }.freeze
12
30
 
31
+ SUPPORTED = NAMED_CURVES.map { |_, c| c[:algorithm] }.uniq.freeze
32
+
13
33
  def sign(to_sign)
14
34
  algorithm, msg, key = to_sign.values
15
- key_algorithm = NAMED_CURVES[key.group.curve_name]
35
+ curve_definition = curve_by_name(key.group.curve_name)
36
+ key_algorithm = curve_definition[:algorithm]
16
37
  if algorithm != key_algorithm
17
38
  raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
18
39
  end
19
40
 
20
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
41
+ digest = OpenSSL::Digest.new(curve_definition[:digest])
21
42
  SecurityUtils.asn1_to_raw(key.dsa_sign_asn1(digest.digest(msg)), key)
22
43
  end
23
44
 
24
45
  def verify(to_verify)
25
46
  algorithm, public_key, signing_input, signature = to_verify.values
26
- key_algorithm = NAMED_CURVES[public_key.group.curve_name]
47
+ curve_definition = curve_by_name(public_key.group.curve_name)
48
+ key_algorithm = curve_definition[:algorithm]
27
49
  if algorithm != key_algorithm
28
50
  raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
29
51
  end
30
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
52
+
53
+ digest = OpenSSL::Digest.new(curve_definition[:digest])
31
54
  public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key))
32
55
  end
56
+
57
+ def curve_by_name(name)
58
+ NAMED_CURVES.fetch(name) do
59
+ raise UnsupportedEcdsaCurve, "The ECDSA curve '#{name}' is not supported"
60
+ end
61
+ end
33
62
  end
34
63
  end
35
64
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Eddsa
@@ -23,6 +25,7 @@ module JWT
23
25
  raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key.primitive} signing key was provided"
24
26
  end
25
27
  raise DecodeError, "key given is a #{public_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey" if public_key.class != RbNaCl::Signatures::Ed25519::VerifyKey
28
+
26
29
  public_key.verify(signature, signing_input)
27
30
  end
28
31
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Hmac
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module None
data/lib/jwt/algos/ps.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Ps
@@ -29,9 +31,7 @@ module JWT
29
31
 
30
32
  def require_openssl!
31
33
  if Object.const_defined?('OpenSSL')
32
- major, minor = OpenSSL::VERSION.split('.').first(2)
33
-
34
- unless major.to_i >= 2 && minor.to_i >= 1
34
+ if ::Gem::Version.new(OpenSSL::VERSION) < ::Gem::Version.new('2.1')
35
35
  raise JWT::RequiredDependencyError, "You currently have OpenSSL #{OpenSSL::VERSION}. PS support requires >= 2.1"
36
36
  end
37
37
  else
data/lib/jwt/algos/rsa.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Rsa
@@ -7,7 +9,8 @@ module JWT
7
9
 
8
10
  def sign(to_sign)
9
11
  algorithm, msg, key = to_sign.values
10
- raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.class == String
12
+ raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.instance_of?(String)
13
+
11
14
  key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
12
15
  end
13
16
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Unsupported
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './error'
2
4
 
3
5
  module JWT
@@ -9,7 +11,7 @@ module JWT
9
11
  ].freeze
10
12
 
11
13
  def initialize(payload)
12
- @payload = payload.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
14
+ @payload = payload.transform_keys(&:to_sym)
13
15
  end
14
16
 
15
17
  def validate!
data/lib/jwt/decode.rb CHANGED
@@ -4,12 +4,14 @@ require 'json'
4
4
 
5
5
  require 'jwt/signature'
6
6
  require 'jwt/verify'
7
+ require 'jwt/x5c_key_finder'
7
8
  # JWT::Decode module
8
9
  module JWT
9
10
  # Decoding logic for JWT
10
11
  class Decode
11
12
  def initialize(jwt, key, verify, options, &keyfinder)
12
13
  raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
14
+
13
15
  @jwt = jwt
14
16
  @key = key
15
17
  @options = options
@@ -23,28 +25,50 @@ module JWT
23
25
  validate_segment_count!
24
26
  if @verify
25
27
  decode_crypto
28
+ verify_algo
29
+ set_key
26
30
  verify_signature
27
31
  verify_claims
28
32
  end
29
33
  raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload
34
+
30
35
  [payload, header]
31
36
  end
32
37
 
33
38
  private
34
39
 
35
40
  def verify_signature
41
+ return unless @key || @verify
42
+
43
+ return if none_algorithm?
44
+
45
+ raise JWT::DecodeError, 'No verification key available' unless @key
46
+
47
+ return if Array(@key).any? { |key| verify_signature_for?(key) }
48
+
49
+ raise(JWT::VerificationError, 'Signature verification failed')
50
+ end
51
+
52
+ def verify_algo
36
53
  raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms.empty?
37
- raise(JWT::IncorrectAlgorithm, 'Token is missing alg header') unless header['alg']
54
+ raise(JWT::IncorrectAlgorithm, 'Token is missing alg header') unless algorithm
38
55
  raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless options_includes_algo_in_header?
56
+ end
39
57
 
58
+ def set_key
40
59
  @key = find_key(&@keyfinder) if @keyfinder
41
60
  @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks]).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
42
65
 
43
- Signature.verify(header['alg'], @key, signing_input, @signature)
66
+ def verify_signature_for?(key)
67
+ Signature.verify(algorithm, key, signing_input, @signature)
44
68
  end
45
69
 
46
70
  def options_includes_algo_in_header?
47
- allowed_algorithms.any? { |alg| alg.casecmp(header['alg']).zero? }
71
+ allowed_algorithms.any? { |alg| alg.casecmp(algorithm).zero? }
48
72
  end
49
73
 
50
74
  def allowed_algorithms
@@ -65,8 +89,10 @@ module JWT
65
89
 
66
90
  def find_key(&keyfinder)
67
91
  key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header))
68
- raise JWT::DecodeError, 'No verification key available' unless key
69
- key
92
+ # key can be of type [string, nil, OpenSSL::PKey, Array]
93
+ return key if key && !Array(key).empty?
94
+
95
+ raise JWT::DecodeError, 'No verification key available'
70
96
  end
71
97
 
72
98
  def verify_claims
@@ -77,7 +103,7 @@ module JWT
77
103
  def validate_segment_count!
78
104
  return if segment_length == 3
79
105
  return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed
80
- return if segment_length == 2 && header['alg'] == 'none'
106
+ return if segment_length == 2 && none_algorithm?
81
107
 
82
108
  raise(JWT::DecodeError, 'Not enough or too many segments')
83
109
  end
@@ -86,8 +112,18 @@ module JWT
86
112
  @segments.count
87
113
  end
88
114
 
115
+ def none_algorithm?
116
+ algorithm.casecmp('none').zero?
117
+ end
118
+
89
119
  def decode_crypto
90
- @signature = JWT::Base64.url_decode(@segments[2] || '')
120
+ @signature = Base64.urlsafe_decode64(@segments[2] || '')
121
+ rescue ArgumentError
122
+ raise(JWT::DecodeError, 'Invalid segment encoding')
123
+ end
124
+
125
+ def algorithm
126
+ header['alg']
91
127
  end
92
128
 
93
129
  def header
@@ -103,8 +139,8 @@ module JWT
103
139
  end
104
140
 
105
141
  def parse_and_decode(segment)
106
- JWT::JSON.parse(JWT::Base64.url_decode(segment))
107
- rescue ::JSON::ParserError
142
+ JWT::JSON.parse(Base64.urlsafe_decode64(segment))
143
+ rescue ::JSON::ParserError, ArgumentError
108
144
  raise JWT::DecodeError, 'Invalid segment encoding'
109
145
  end
110
146
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module DefaultOptions
3
5
  DEFAULT_OPTIONS = {
data/lib/jwt/encode.rb CHANGED
@@ -7,14 +7,14 @@ require_relative './claims_validator'
7
7
  module JWT
8
8
  # Encoding logic for JWT
9
9
  class Encode
10
- ALG_NONE = 'none'.freeze
11
- ALG_KEY = 'alg'.freeze
10
+ ALG_NONE = 'none'
11
+ ALG_KEY = 'alg'
12
12
 
13
13
  def initialize(options)
14
14
  @payload = options[:payload]
15
15
  @key = options[:key]
16
16
  _, @algorithm = Algos.find(options[:algorithm])
17
- @headers = options[:headers].each_with_object({}) { |(key, value), headers| headers[key.to_s] = value }
17
+ @headers = options[:headers].transform_keys(&:to_s)
18
18
  end
19
19
 
20
20
  def segments
@@ -45,7 +45,7 @@ module JWT
45
45
  end
46
46
 
47
47
  def encode_payload
48
- if @payload && @payload.is_a?(Hash)
48
+ if @payload.is_a?(Hash)
49
49
  ClaimsValidator.new(@payload).validate!
50
50
  end
51
51
 
@@ -55,11 +55,11 @@ module JWT
55
55
  def encode_signature
56
56
  return '' if @algorithm == ALG_NONE
57
57
 
58
- JWT::Base64.url_encode(JWT::Signature.sign(@algorithm, encoded_header_and_payload, @key))
58
+ Base64.urlsafe_encode64(JWT::Signature.sign(@algorithm, encoded_header_and_payload, @key), padding: false)
59
59
  end
60
60
 
61
61
  def encode(data)
62
- JWT::Base64.url_encode(JWT::JSON.generate(data))
62
+ Base64.urlsafe_encode64(JWT::JSON.generate(data), padding: false)
63
63
  end
64
64
 
65
65
  def combine(*parts)
data/lib/jwt/error.rb CHANGED
@@ -10,6 +10,7 @@ module JWT
10
10
  class IncorrectAlgorithm < DecodeError; end
11
11
  class ImmatureSignature < DecodeError; end
12
12
  class InvalidIssuerError < DecodeError; end
13
+ class UnsupportedEcdsaCurve < IncorrectAlgorithm; end
13
14
  class InvalidIatError < DecodeError; end
14
15
  class InvalidAudError < DecodeError; end
15
16
  class InvalidSubError < DecodeError; end
data/lib/jwt/jwk/ec.rb CHANGED
@@ -8,7 +8,7 @@ module JWT
8
8
  extend Forwardable
9
9
  def_delegators :@keypair, :public_key
10
10
 
11
- KTY = 'EC'.freeze
11
+ KTY = 'EC'
12
12
  KTYS = [KTY, OpenSSL::PKey::EC].freeze
13
13
  BINARY = 2
14
14
 
@@ -59,6 +59,9 @@ module JWT
59
59
  when 'prime256v1'
60
60
  crv = 'P-256'
61
61
  x_octets, y_octets = encoded_point.unpack('xa32a32')
62
+ when 'secp256k1'
63
+ crv = 'P-256K'
64
+ x_octets, y_octets = encoded_point.unpack('xa32a32')
62
65
  when 'secp384r1'
63
66
  crv = 'P-384'
64
67
  x_octets, y_octets = encoded_point.unpack('xa48a48')
@@ -72,11 +75,11 @@ module JWT
72
75
  end
73
76
 
74
77
  def encode_octets(octets)
75
- ::JWT::Base64.url_encode(octets)
78
+ Base64.urlsafe_encode64(octets, padding: false)
76
79
  end
77
80
 
78
81
  def encode_open_ssl_bn(key_part)
79
- ::JWT::Base64.url_encode(key_part.to_s(BINARY))
82
+ Base64.urlsafe_encode64(key_part.to_s(BINARY), padding: false)
80
83
  end
81
84
 
82
85
  class << self
@@ -98,6 +101,7 @@ module JWT
98
101
  when 'P-256' then 'prime256v1'
99
102
  when 'P-384' then 'secp384r1'
100
103
  when 'P-521' then 'secp521r1'
104
+ when 'P-256K' then 'secp256k1'
101
105
  else raise JWT::JWKError, 'Invalid curve provided'
102
106
  end
103
107
  end
@@ -138,11 +142,11 @@ module JWT
138
142
  end
139
143
 
140
144
  def decode_octets(jwk_data)
141
- ::JWT::Base64.url_decode(jwk_data)
145
+ Base64.urlsafe_decode64(jwk_data)
142
146
  end
143
147
 
144
148
  def decode_open_ssl_bn(jwk_data)
145
- OpenSSL::BN.new(::JWT::Base64.url_decode(jwk_data), BINARY)
149
+ OpenSSL::BN.new(Base64.urlsafe_decode64(jwk_data), BINARY)
146
150
  end
147
151
  end
148
152
  end
data/lib/jwt/jwk/hmac.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module JWT
4
4
  module JWK
5
5
  class HMAC < KeyBase
6
- KTY = 'oct'.freeze
6
+ KTY = 'oct'
7
7
  KTYS = [KTY, String].freeze
8
8
 
9
9
  def initialize(keypair, kid = nil)
@@ -50,7 +50,7 @@ module JWT
50
50
 
51
51
  raise JWT::JWKError, 'Key format is invalid for HMAC' unless jwk_k
52
52
 
53
- self.new(jwk_k, jwk_kid)
53
+ new(jwk_k, jwk_kid)
54
54
  end
55
55
  end
56
56
  end
@@ -11,6 +11,7 @@ module JWT
11
11
  end
12
12
 
13
13
  def self.inherited(klass)
14
+ super
14
15
  ::JWT::JWK.classes << klass
15
16
  end
16
17
  end
data/lib/jwt/jwk/rsa.rb CHANGED
@@ -4,12 +4,13 @@ module JWT
4
4
  module JWK
5
5
  class RSA < KeyBase
6
6
  BINARY = 2
7
- KTY = 'RSA'.freeze
7
+ KTY = 'RSA'
8
8
  KTYS = [KTY, OpenSSL::PKey::RSA].freeze
9
9
  RSA_KEY_ELEMENTS = %i[n e d p q dp dq qi].freeze
10
10
 
11
11
  def initialize(keypair, kid = nil)
12
12
  raise ArgumentError, 'keypair must be of type OpenSSL::PKey::RSA' unless keypair.is_a?(OpenSSL::PKey::RSA)
13
+
13
14
  super(keypair, kid || generate_kid(keypair.public_key))
14
15
  end
15
16
 
@@ -54,7 +55,7 @@ module JWT
54
55
  end
55
56
 
56
57
  def encode_open_ssl_bn(key_part)
57
- ::JWT::Base64.url_encode(key_part.to_s(BINARY))
58
+ Base64.urlsafe_encode64(key_part.to_s(BINARY), padding: false)
58
59
  end
59
60
 
60
61
  class << self
@@ -63,7 +64,7 @@ module JWT
63
64
  decode_open_ssl_bn(value)
64
65
  end
65
66
  kid = jwk_attributes(jwk_data, :kid)[:kid]
66
- self.new(rsa_pkey(pkey_params), kid)
67
+ new(rsa_pkey(pkey_params), kid)
67
68
  end
68
69
 
69
70
  private
@@ -107,7 +108,7 @@ module JWT
107
108
  def decode_open_ssl_bn(jwk_data)
108
109
  return nil unless jwk_data
109
110
 
110
- OpenSSL::BN.new(::JWT::Base64.url_decode(jwk_data), BINARY)
111
+ OpenSSL::BN.new(Base64.urlsafe_decode64(jwk_data), BINARY)
111
112
  end
112
113
  end
113
114
  end
data/lib/jwt/jwk.rb CHANGED
@@ -36,6 +36,7 @@ module JWT
36
36
  def generate_mappings
37
37
  classes.each_with_object({}) do |klass, hash|
38
38
  next unless klass.const_defined?('KTYS')
39
+
39
40
  Array(klass::KTYS).each do |kty|
40
41
  hash[kty] = klass
41
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  # Collection of security methods
3
5
  #