jwt 1.5.6 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8cd1a9ca017dec28c4984e18003e8ae58aee776c
4
- data.tar.gz: c5fef77f9a8e42d8fa92c060c468be6ee2e3c561
3
+ metadata.gz: f874da696e03e2c7f0ffe02942540825eb8a6314
4
+ data.tar.gz: d57f6842df5cc35d21bea1a1e511026faeb0aaa4
5
5
  SHA512:
6
- metadata.gz: c0dc92b0ea35004782c8260f8d2d47c9973a1172f5eb6bef33fe42ae3a2e8341c9264e5fafc7cb62442039409194c3aa6fbd3db78667db75af04ffd26586422f
7
- data.tar.gz: af9967d4c04b332ef8916d3b837e31c20b2e5db8c96531b277286324f29730edbc65eb66401f6db405b22dbd2701895d2579796fab368c26bd1fca58aae30840
6
+ metadata.gz: 51acfa10b330d62022d463cd4c0d25eff3ceb642b29e2c625d4aab40cd1a4138ca5597e0e19d540232f3f3b2e76fdcf4b403566f5b54aa7e687ab7d8696186e6
7
+ data.tar.gz: b8d9b8f1485f4e0c74d189c1e7ba64d71ce89f4813b134dbaf28263c695403dd102f12ab9dddde0ee7990f6cbcfde5ab5941876919bb1540b4088349129d1baf
@@ -1,2 +1,5 @@
1
+ AllCops:
2
+ Excludes:
3
+ - spec/**/*
1
4
  Metrics/LineLength:
2
5
  Enabled: false
@@ -1,13 +1,13 @@
1
- sudo: false
1
+ sudo: required
2
2
  cache: bundler
3
3
  language: ruby
4
4
  rvm:
5
- - 1.9.3
6
- - 2.0.0
7
- - 2.1.0
8
5
  - 2.2.0
9
6
  - 2.3.0
10
- script: "bundle exec rspec"
11
- addons:
12
- code_climate:
13
- repo_token: e87b175db123ab42ca2ca4420abaa13c0dc2085608402b9a25f08a83ca3ba202
7
+ - 2.4.0
8
+ script: "bundle exec rspec && bundle exec codeclimate-test-reporter"
9
+ before_install:
10
+ - sudo add-apt-repository ppa:chris-lea/libsodium -y
11
+ - sudo apt-get update -q
12
+ - sudo apt-get install libsodium-dev -y
13
+ - gem install bundler
@@ -1,5 +1,52 @@
1
1
  # Change Log
2
2
 
3
+ ## [v2.0.0](https://github.com/jwt/ruby-jwt/tree/v2.0.0) (2017-02-27)
4
+ [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.6...v2.0.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Error with method sign for String [\#171](https://github.com/jwt/ruby-jwt/issues/171)
9
+ - Refactor the encondig code [\#121](https://github.com/jwt/ruby-jwt/issues/121)
10
+ - Refactor [\#196](https://github.com/jwt/ruby-jwt/pull/196) ([EmilioCristalli](https://github.com/EmilioCristalli))
11
+ - Move signature logic to its own module [\#195](https://github.com/jwt/ruby-jwt/pull/195) ([EmilioCristalli](https://github.com/EmilioCristalli))
12
+ - Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli))
13
+ - Add user friendly encode error if private key is a String, \#171 [\#176](https://github.com/jwt/ruby-jwt/pull/176) ([xamenrax](https://github.com/xamenrax))
14
+ - Return empty string if signature less than byte\_size \#155 [\#175](https://github.com/jwt/ruby-jwt/pull/175) ([xamenrax](https://github.com/xamenrax))
15
+ - Remove 'typ' optional parameter [\#174](https://github.com/jwt/ruby-jwt/pull/174) ([xamenrax](https://github.com/xamenrax))
16
+ - Pass payload to keyfinder [\#172](https://github.com/jwt/ruby-jwt/pull/172) ([CodeMonkeySteve](https://github.com/CodeMonkeySteve))
17
+ - Use RbNaCl for HMAC if available with fallback to OpenSSL [\#149](https://github.com/jwt/ruby-jwt/pull/149) ([mwpastore](https://github.com/mwpastore))
18
+
19
+ **Fixed bugs:**
20
+
21
+ - ruby-jwt::raw\_to\_asn1: Fails for signatures less than byte\_size [\#155](https://github.com/jwt/ruby-jwt/issues/155)
22
+ - The leeway parameter is applies to all time based verifications [\#129](https://github.com/jwt/ruby-jwt/issues/129)
23
+ - Add options for claim-specific leeway [\#187](https://github.com/jwt/ruby-jwt/pull/187) ([EmilioCristalli](https://github.com/EmilioCristalli))
24
+ - Make algorithm option required to verify signature [\#184](https://github.com/jwt/ruby-jwt/pull/184) ([EmilioCristalli](https://github.com/EmilioCristalli))
25
+ - Validate audience when payload is a scalar and options is an array [\#183](https://github.com/jwt/ruby-jwt/pull/183) ([steti](https://github.com/steti))
26
+
27
+ **Closed issues:**
28
+
29
+ - Different encoded value between servers with same password [\#197](https://github.com/jwt/ruby-jwt/issues/197)
30
+ - Signature is different at each run [\#190](https://github.com/jwt/ruby-jwt/issues/190)
31
+ - Include custom headers with password [\#189](https://github.com/jwt/ruby-jwt/issues/189)
32
+ - can't create token - 'NotImplementedError: Unsupported signing method' [\#186](https://github.com/jwt/ruby-jwt/issues/186)
33
+ - Why jwt depends on json \< 2.0 ? [\#179](https://github.com/jwt/ruby-jwt/issues/179)
34
+ - Cannot verify JWT at all?? [\#177](https://github.com/jwt/ruby-jwt/issues/177)
35
+ - verify\_iss: true is raising JWT::DecodeError instead of JWT::InvalidIssuerError [\#170](https://github.com/jwt/ruby-jwt/issues/170)
36
+
37
+ **Merged pull requests:**
38
+
39
+ - Add Codacy coverage reporter [\#194](https://github.com/jwt/ruby-jwt/pull/194) ([excpt](https://github.com/excpt))
40
+ - Add minimum required ruby version to gemspec [\#193](https://github.com/jwt/ruby-jwt/pull/193) ([excpt](https://github.com/excpt))
41
+ - Code smell fixes [\#192](https://github.com/jwt/ruby-jwt/pull/192) ([excpt](https://github.com/excpt))
42
+ - Version bump to 2.0.0.dev [\#191](https://github.com/jwt/ruby-jwt/pull/191) ([excpt](https://github.com/excpt))
43
+ - Basic encode module refactoring \#121 [\#182](https://github.com/jwt/ruby-jwt/pull/182) ([xamenrax](https://github.com/xamenrax))
44
+ - Fix travis ci build configuration [\#181](https://github.com/jwt/ruby-jwt/pull/181) ([excpt](https://github.com/excpt))
45
+ - Fix travis ci build configuration [\#180](https://github.com/jwt/ruby-jwt/pull/180) ([excpt](https://github.com/excpt))
46
+ - Fix typo in README [\#178](https://github.com/jwt/ruby-jwt/pull/178) ([tomeduarte](https://github.com/tomeduarte))
47
+ - Fix code style [\#173](https://github.com/jwt/ruby-jwt/pull/173) ([excpt](https://github.com/excpt))
48
+ - Fixed a typo in a spec name [\#169](https://github.com/jwt/ruby-jwt/pull/169) ([Mingan](https://github.com/Mingan))
49
+
3
50
  ## [v1.5.6](https://github.com/jwt/ruby-jwt/tree/v1.5.6) (2016-09-19)
4
51
  [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v1.5.5...v1.5.6)
5
52
 
@@ -9,6 +56,7 @@
9
56
 
10
57
  **Merged pull requests:**
11
58
 
59
+ - Update changelog [\#168](https://github.com/jwt/ruby-jwt/pull/168) ([excpt](https://github.com/excpt))
12
60
  - Fix rubocop code smells [\#167](https://github.com/jwt/ruby-jwt/pull/167) ([excpt](https://github.com/excpt))
13
61
 
14
62
  ## [v1.5.5](https://github.com/jwt/ruby-jwt/tree/v1.5.5) (2016-09-16)
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  A pure ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard.
9
9
 
10
- If you have further questions releated to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
10
+ If you have further questions related to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
11
11
 
12
12
  ## Announcements
13
13
 
@@ -55,7 +55,7 @@ decoded_token = JWT.decode token, nil, false
55
55
  # Array
56
56
  # [
57
57
  # {"data"=>"test"}, # payload
58
- # {"typ"=>"JWT", "alg"=>"none"} # header
58
+ # {"alg"=>"none"} # header
59
59
  # ]
60
60
  puts decoded_token
61
61
  ```
@@ -63,6 +63,7 @@ puts decoded_token
63
63
  **HMAC** (default: HS256)
64
64
 
65
65
  * HS256 - HMAC using SHA-256 hash algorithm (default)
66
+ * HS512256 - HMAC using SHA-512/256 hash algorithm (only available with RbNaCl; see note below)
66
67
  * HS384 - HMAC using SHA-384 hash algorithm
67
68
  * HS512 - HMAC using SHA-512 hash algorithm
68
69
 
@@ -79,11 +80,13 @@ decoded_token = JWT.decode token, hmac_secret, true, { :algorithm => 'HS256' }
79
80
  # Array
80
81
  # [
81
82
  # {"data"=>"test"}, # payload
82
- # {"typ"=>"JWT", "alg"=>"HS256"} # header
83
+ # {"alg"=>"HS256"} # header
83
84
  # ]
84
85
  puts decoded_token
85
86
  ```
86
87
 
88
+ Note: If [RbNaCl](https://github.com/cryptosphere/rbnacl) is loadable, ruby-jwt will use it for HMAC-SHA256, HMAC-SHA512/256, and HMAC-SHA512. RbNaCl enforces a maximum key size of 32 bytes for these algorithms.
89
+
87
90
  **RSA**
88
91
 
89
92
  * RS256 - RSA using SHA-256 hash algorithm
@@ -104,7 +107,7 @@ decoded_token = JWT.decode token, rsa_public, true, { :algorithm => 'RS256' }
104
107
  # Array
105
108
  # [
106
109
  # {"data"=>"test"}, # payload
107
- # {"typ"=>"JWT", "alg"=>"RS256"} # header
110
+ # {"alg"=>"RS256"} # header
108
111
  # ]
109
112
  puts decoded_token
110
113
  ```
@@ -131,7 +134,7 @@ decoded_token = JWT.decode token, ecdsa_public, true, { :algorithm => 'ES256' }
131
134
  # Array
132
135
  # [
133
136
  # {"test"=>"data"}, # payload
134
- # {"typ"=>"JWT", "alg"=>"ES256"} # header
137
+ # {"alg"=>"ES256"} # header
135
138
  # ]
136
139
  puts decoded_token
137
140
  ```
@@ -152,6 +155,38 @@ used. JWT supports these reserved claim names:
152
155
  - 'iat' (Issued At) Claim
153
156
  - 'sub' (Subject) Claim
154
157
 
158
+ ## Add custom header fields
159
+ Ruby-jwt gem supports custom [header fields] (https://tools.ietf.org/html/rfc7519#section-5)
160
+ To add custom header fields you need to pass `header_fields` parameter
161
+
162
+ ```ruby
163
+ token = JWT.encode payload, key, algorithm='HS256', header_fields={}
164
+ ```
165
+
166
+ **Example:**
167
+
168
+ ```ruby
169
+ require 'jwt'
170
+
171
+ payload = {:data => 'test'}
172
+
173
+ # IMPORTANT: set nil as password parameter
174
+ token = JWT.encode payload, nil, 'none', { :typ => "JWT" }
175
+
176
+ # eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.
177
+ puts token
178
+
179
+ # Set password to nil and validation to false otherwise this won't work
180
+ decoded_token = JWT.decode token, nil, false
181
+
182
+ # Array
183
+ # [
184
+ # {"data"=>"test"}, # payload
185
+ # {"typ"=>"JWT", "alg"=>"none"} # header
186
+ # ]
187
+ puts decoded_token
188
+ ```
189
+
155
190
  ### Expiration Time Claim
156
191
 
157
192
  From [Oauth JSON Web Token 4.1.4. "exp" (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4):
@@ -186,7 +221,7 @@ token = JWT.encode exp_payload, hmac_secret, 'HS256'
186
221
 
187
222
  begin
188
223
  # add leeway to ensure the token is still accepted
189
- decoded_token = JWT.decode token, hmac_secret, true, { :leeway => leeway, :algorithm => 'HS256' }
224
+ decoded_token = JWT.decode token, hmac_secret, true, { :exp_leeway => leeway, :algorithm => 'HS256' }
190
225
  rescue JWT::ExpiredSignature
191
226
  # Handle expired token, e.g. logout user or deny access
192
227
  end
@@ -226,7 +261,7 @@ token = JWT.encode nbf_payload, hmac_secret, 'HS256'
226
261
 
227
262
  begin
228
263
  # add leeway to ensure the token is valid
229
- decoded_token = JWT.decode token, hmac_secret, true, { :leeway => leeway, :algorithm => 'HS256' }
264
+ decoded_token = JWT.decode token, hmac_secret, true, { :nbf_leeway => leeway, :algorithm => 'HS256' }
230
265
  rescue JWT::ImmatureSignature
231
266
  # Handle invalid token, e.g. logout user or deny access
232
267
  end
@@ -305,6 +340,8 @@ From [Oauth JSON Web Token 4.1.6. "iat" (Issued At) Claim](https://tools.ietf.or
305
340
 
306
341
  > The `iat` (issued at) claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT. Its value MUST be a number containing a ***NumericDate*** value. Use of this claim is OPTIONAL.
307
342
 
343
+ **Handle Issued At Claim**
344
+
308
345
  ```ruby
309
346
  iat = Time.now.to_i
310
347
  iat_payload = { :data => 'data', :iat => iat }
@@ -319,6 +356,25 @@ rescue JWT::InvalidIatError
319
356
  end
320
357
  ```
321
358
 
359
+ **Adding Leeway**
360
+
361
+ ```ruby
362
+ iat = Time.now.to_i + 10
363
+ leeway = 30 # seconds
364
+
365
+ iat_payload = { :data => 'data', :iat => iat }
366
+
367
+ # build token issued in the future
368
+ token = JWT.encode iat_payload, hmac_secret, 'HS256'
369
+
370
+ begin
371
+ # add leeway to ensure the token is accepted
372
+ decoded_token = JWT.decode token, hmac_secret, true, { :iat_leeway => leeway, :verify_iat => true, :algorithm => 'HS256' }
373
+ rescue JWT::InvalidIatError
374
+ # Handle invalid token, e.g. logout user or deny access
375
+ end
376
+ ```
377
+
322
378
  ### Subject Claim
323
379
 
324
380
  From [Oauth JSON Web Token 4.1.2. "sub" (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2):
data/lib/jwt.rb CHANGED
@@ -1,192 +1,67 @@
1
1
  # frozen_string_literal: true
2
2
  require 'base64'
3
- require 'openssl'
4
3
  require 'jwt/decode'
4
+ require 'jwt/default_options'
5
+ require 'jwt/encode'
5
6
  require 'jwt/error'
6
- require 'jwt/json'
7
+ require 'jwt/signature'
8
+ require 'jwt/verify'
7
9
 
8
10
  # JSON Web Token implementation
9
11
  #
10
12
  # Should be up to date with the latest spec:
11
- # https://tools.ietf.org/html/rfc7519#section-4.1.5
13
+ # https://tools.ietf.org/html/rfc7519
12
14
  module JWT
13
- extend JWT::Json
14
-
15
- NAMED_CURVES = {
16
- 'prime256v1' => 'ES256',
17
- 'secp384r1' => 'ES384',
18
- 'secp521r1' => 'ES512'
19
- }.freeze
20
-
21
- DEFAULT_OPTIONS = {
22
- verify_expiration: true,
23
- verify_not_before: true,
24
- verify_iss: false,
25
- verify_iat: false,
26
- verify_jti: false,
27
- verify_aud: false,
28
- verify_sub: false,
29
- leeway: 0
30
- }.freeze
15
+ include JWT::DefaultOptions
31
16
 
32
17
  module_function
33
18
 
34
- def sign(algorithm, msg, key)
35
- if %w(HS256 HS384 HS512).include?(algorithm)
36
- sign_hmac(algorithm, msg, key)
37
- elsif %w(RS256 RS384 RS512).include?(algorithm)
38
- sign_rsa(algorithm, msg, key)
39
- elsif %w(ES256 ES384 ES512).include?(algorithm)
40
- sign_ecdsa(algorithm, msg, key)
41
- else
42
- raise NotImplementedError, 'Unsupported signing method'
43
- end
44
- end
45
-
46
- def sign_rsa(algorithm, msg, private_key)
47
- private_key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
48
- end
49
-
50
- def sign_ecdsa(algorithm, msg, private_key)
51
- key_algorithm = NAMED_CURVES[private_key.group.curve_name]
52
- if algorithm != key_algorithm
53
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
54
- end
55
-
56
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
57
- asn1_to_raw(private_key.dsa_sign_asn1(digest.digest(msg)), private_key)
58
- end
59
-
60
- def verify_rsa(algorithm, public_key, signing_input, signature)
61
- public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input)
62
- end
63
-
64
- def verify_ecdsa(algorithm, public_key, signing_input, signature)
65
- key_algorithm = NAMED_CURVES[public_key.group.curve_name]
66
- if algorithm != key_algorithm
67
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
68
- end
69
-
70
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
71
- public_key.dsa_verify_asn1(digest.digest(signing_input), raw_to_asn1(signature, public_key))
72
- end
73
-
74
- def sign_hmac(algorithm, msg, key)
75
- OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
76
- end
77
-
78
- def base64url_encode(str)
79
- Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '')
80
- end
81
-
82
- def encoded_header(algorithm = 'HS256', header_fields = {})
83
- header = { 'typ' => 'JWT', 'alg' => algorithm }.merge(header_fields)
84
- base64url_encode(encode_json(header))
85
- end
86
-
87
- def encoded_payload(payload)
88
- raise InvalidPayload, 'exp claim must be an integer' if payload['exp'] && payload['exp'].is_a?(Time)
89
- base64url_encode(encode_json(payload))
90
- end
19
+ def decoded_segments(jwt, verify = true)
20
+ raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
91
21
 
92
- def encoded_signature(signing_input, key, algorithm)
93
- if algorithm == 'none'
94
- ''
95
- else
96
- signature = sign(algorithm, signing_input, key)
97
- base64url_encode(signature)
98
- end
22
+ decoder = Decode.new jwt, verify
23
+ decoder.decode_segments
99
24
  end
100
25
 
101
26
  def encode(payload, key, algorithm = 'HS256', header_fields = {})
102
- algorithm ||= 'none'
103
- segments = []
104
- segments << encoded_header(algorithm, header_fields)
105
- segments << encoded_payload(payload)
106
- segments << encoded_signature(segments.join('.'), key, algorithm)
107
- segments.join('.')
108
- end
109
-
110
- def decoded_segments(jwt, key = nil, verify = true, custom_options = {}, &keyfinder)
111
- raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
112
-
113
- merged_options = DEFAULT_OPTIONS.merge(custom_options)
114
-
115
- decoder = Decode.new jwt, key, verify, merged_options, &keyfinder
116
- decoder.decode_segments
27
+ encoder = Encode.new payload, key, algorithm, header_fields
28
+ encoder.segments
117
29
  end
118
30
 
119
31
  def decode(jwt, key = nil, verify = true, custom_options = {}, &keyfinder)
120
32
  raise(JWT::DecodeError, 'Nil JSON web token') unless jwt
121
33
 
122
34
  merged_options = DEFAULT_OPTIONS.merge(custom_options)
123
- decoder = Decode.new jwt, key, verify, merged_options, &keyfinder
35
+
36
+ decoder = Decode.new jwt, verify
124
37
  header, payload, signature, signing_input = decoder.decode_segments
125
- decode_verify_signature(key, header, signature, signing_input, merged_options, &keyfinder) if verify
126
- decoder.verify
38
+ decode_verify_signature(key, header, payload, signature, signing_input, merged_options, &keyfinder) if verify
39
+
40
+ Verify.verify_claims(payload, merged_options)
127
41
 
128
42
  raise(JWT::DecodeError, 'Not enough or too many segments') unless header && payload
129
43
 
130
44
  [payload, header]
131
45
  end
132
46
 
133
- def decode_verify_signature(key, header, signature, signing_input, options, &keyfinder)
134
- algo, key = signature_algorithm_and_key(header, key, &keyfinder)
135
- if options[:algorithm] && algo != options[:algorithm]
136
- raise JWT::IncorrectAlgorithm, 'Expected a different algorithm'
137
- end
138
- verify_signature(algo, key, signing_input, signature)
139
- end
47
+ def decode_verify_signature(key, header, payload, signature, signing_input, options, &keyfinder)
48
+ algo, key = signature_algorithm_and_key(header, payload, key, &keyfinder)
140
49
 
141
- def signature_algorithm_and_key(header, key, &keyfinder)
142
- key = yield(header) if keyfinder
143
- [header['alg'], key]
144
- end
50
+ raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') unless options[:algorithm]
51
+ raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless algo == options[:algorithm]
145
52
 
146
- def verify_signature(algo, key, signing_input, signature)
147
- verify_signature_algo(algo, key, signing_input, signature)
148
- rescue OpenSSL::PKey::PKeyError
149
- raise JWT::VerificationError, 'Signature verification raised'
150
- ensure
151
- OpenSSL.errors.clear
53
+ Signature.verify(algo, key, signing_input, signature)
152
54
  end
153
55
 
154
- def verify_signature_algo(algo, key, signing_input, signature)
155
- if %w(HS256 HS384 HS512).include?(algo)
156
- raise(JWT::VerificationError, 'Signature verification raised') unless secure_compare(signature, sign_hmac(algo, signing_input, key))
157
- elsif %w(RS256 RS384 RS512).include?(algo)
158
- raise(JWT::VerificationError, 'Signature verification raised') unless verify_rsa(algo, key, signing_input, signature)
159
- elsif %w(ES256 ES384 ES512).include?(algo)
160
- raise(JWT::VerificationError, 'Signature verification raised') unless verify_ecdsa(algo, key, signing_input, signature)
161
- else
162
- raise JWT::VerificationError, 'Algorithm not supported'
56
+ def signature_algorithm_and_key(header, payload, key, &keyfinder)
57
+ if keyfinder
58
+ key = if keyfinder.arity == 2
59
+ yield(header, payload)
60
+ else
61
+ yield(header)
62
+ end
63
+ raise JWT::DecodeError, 'No verification key available' unless key
163
64
  end
164
- end
165
-
166
- # From devise
167
- # constant-time comparison algorithm to prevent timing attacks
168
- def secure_compare(a, b)
169
- return false if a.nil? || b.nil? || a.empty? || b.empty? || a.bytesize != b.bytesize
170
- l = a.unpack "C#{a.bytesize}"
171
-
172
- res = 0
173
- b.each_byte { |byte| res |= byte ^ l.shift }
174
- res.zero?
175
- end
176
-
177
- def raw_to_asn1(signature, private_key)
178
- byte_size = (private_key.group.degree + 7) / 8
179
- r = signature[0..(byte_size - 1)]
180
- s = signature[byte_size..-1]
181
- OpenSSL::ASN1::Sequence.new([r, s].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
182
- end
183
-
184
- def asn1_to_raw(signature, public_key)
185
- byte_size = (public_key.group.degree + 7) / 8
186
- OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
187
- end
188
-
189
- def base64url_decode(str)
190
- Decode.base64url_decode(str)
65
+ [header['alg'], key]
191
66
  end
192
67
  end