json-jwt 1.10.0 → 1.13.0
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.
Potentially problematic release.
This version of json-jwt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/VERSION +1 -1
- data/json-jwt.gemspec +4 -3
- data/lib/json/jose.rb +4 -2
- data/lib/json/jwe.rb +11 -10
- data/lib/json/jwk.rb +14 -12
- data/lib/json/jwk/jwkizable.rb +2 -0
- data/lib/json/jws.rb +20 -22
- metadata +5 -48
- data/spec/fixtures/ecdsa/256/private_key.pem +0 -5
- data/spec/fixtures/ecdsa/256/public_key.pem +0 -4
- data/spec/fixtures/ecdsa/384/private_key.pem +0 -6
- data/spec/fixtures/ecdsa/384/public_key.pem +0 -5
- data/spec/fixtures/ecdsa/512/private_key.pem +0 -7
- data/spec/fixtures/ecdsa/512/public_key.pem +0 -6
- data/spec/fixtures/rsa/private_key.der +0 -0
- data/spec/fixtures/rsa/private_key.pem +0 -30
- data/spec/fixtures/rsa/public_key.pem +0 -8
- data/spec/helpers/nimbus_spec_helper.rb +0 -22
- data/spec/helpers/sign_key_fixture_helper.rb +0 -52
- data/spec/interop/with_jsrsasign_spec.rb +0 -49
- data/spec/interop/with_nimbus_jose_spec.rb +0 -99
- data/spec/interop/with_rfc_example_spec.rb +0 -19
- data/spec/json/jwe_spec.rb +0 -351
- data/spec/json/jwk/jwkizable_spec.rb +0 -49
- data/spec/json/jwk/set_spec.rb +0 -75
- data/spec/json/jwk_spec.rb +0 -194
- data/spec/json/jws_spec.rb +0 -440
- data/spec/json/jwt_spec.rb +0 -523
- data/spec/spec_helper.rb +0 -28
data/spec/json/jwt_spec.rb
DELETED
@@ -1,523 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe JSON::JWT do
|
4
|
-
let(:jwt) { JSON::JWT.new claims }
|
5
|
-
let(:jws) do
|
6
|
-
jwt.alg = :HS256
|
7
|
-
jws = JSON::JWS.new jwt
|
8
|
-
jws.signature = 'signature'
|
9
|
-
jws
|
10
|
-
end
|
11
|
-
let(:claims) do
|
12
|
-
{
|
13
|
-
iss: 'joe',
|
14
|
-
exp: 1300819380,
|
15
|
-
'http://example.com/is_root' => true
|
16
|
-
}.with_indifferent_access
|
17
|
-
end
|
18
|
-
let(:no_signed) do
|
19
|
-
'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'when not signed nor encrypted' do
|
23
|
-
it do
|
24
|
-
jwt.to_s.should == no_signed
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe '#content_type' do
|
29
|
-
it do
|
30
|
-
jwt.content_type.should == 'application/jwt'
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe '#sign' do
|
35
|
-
[:HS256, :HS384, :HS512].each do |algorithm|
|
36
|
-
context algorithm do
|
37
|
-
it do
|
38
|
-
jwt.sign(shared_secret, algorithm).should be_a JSON::JWS
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
[:RS256, :RS384, :RS512].each do |algorithm|
|
44
|
-
context algorithm do
|
45
|
-
it do
|
46
|
-
jwt.sign(private_key, algorithm).should be_a JSON::JWS
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'when no algirithm specified' do
|
52
|
-
subject { jwt.sign(key) }
|
53
|
-
|
54
|
-
context 'when key is String' do
|
55
|
-
let(:key) { shared_secret }
|
56
|
-
its(:alg) { should == :HS256 }
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'when key is RSA key' do
|
60
|
-
let(:key) { private_key }
|
61
|
-
its(:alg) { should == :RS256 }
|
62
|
-
end
|
63
|
-
|
64
|
-
context 'when key is EC key' do
|
65
|
-
context 'when prime256v1' do
|
66
|
-
let(:key) { private_key(:ecdsa) }
|
67
|
-
its(:alg) { should == :ES256 }
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'when secp384r1' do
|
71
|
-
let(:key) { private_key(:ecdsa, digest_length: 384) }
|
72
|
-
its(:alg) { should == :ES384 }
|
73
|
-
end
|
74
|
-
|
75
|
-
context 'when secp521r1' do
|
76
|
-
let(:key) { private_key(:ecdsa, digest_length: 512) }
|
77
|
-
its(:alg) { should == :ES512 }
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
context 'when key is JWK with kty=okt' do
|
82
|
-
let(:key) { JSON::JWK.new shared_secret }
|
83
|
-
its(:alg) { should == :HS256 }
|
84
|
-
end
|
85
|
-
|
86
|
-
context 'when key is JWK with kty=RSA' do
|
87
|
-
let(:key) { JSON::JWK.new private_key }
|
88
|
-
its(:alg) { should == :RS256 }
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'when key is JWK with kty=EC' do
|
92
|
-
context 'when prime256v1' do
|
93
|
-
let(:key) { JSON::JWK.new private_key(:ecdsa) }
|
94
|
-
its(:alg) { should == :ES256 }
|
95
|
-
end
|
96
|
-
|
97
|
-
context 'when secp384r1' do
|
98
|
-
let(:key) { JSON::JWK.new private_key(:ecdsa, digest_length: 384) }
|
99
|
-
its(:alg) { should == :ES384 }
|
100
|
-
end
|
101
|
-
|
102
|
-
context 'when secp521r1' do
|
103
|
-
let(:key) { JSON::JWK.new private_key(:ecdsa, digest_length: 512) }
|
104
|
-
its(:alg) { should == :ES512 }
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
context 'when non-JWK key is given' do
|
110
|
-
let(:key) { private_key }
|
111
|
-
it 'should not set kid header automatically' do
|
112
|
-
jws = jwt.sign(key, :RS256)
|
113
|
-
jws.kid.should be_blank
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
context 'when JWK is given' do
|
118
|
-
let(:key) { JSON::JWK.new private_key }
|
119
|
-
it 'should set kid header automatically' do
|
120
|
-
jws = jwt.sign(key, :RS256)
|
121
|
-
jwt.kid.should be_blank
|
122
|
-
jws.kid.should == key[:kid]
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe 'object copy behaviour' do
|
127
|
-
before do
|
128
|
-
@jwt = JSON::JWT.new(obj: {foo: :bar})
|
129
|
-
@jws = @jwt.sign('secret')
|
130
|
-
end
|
131
|
-
|
132
|
-
context 'when original JWT is modified' do
|
133
|
-
before do
|
134
|
-
@jwt.header[:x] = :x
|
135
|
-
@jwt[:obj][:x] = :x
|
136
|
-
end
|
137
|
-
|
138
|
-
describe 'copied JWS' do
|
139
|
-
it 'should be affected as shallow copy, but not as a simple reference' do
|
140
|
-
@jws.header.should_not include :x
|
141
|
-
@jws[:obj].should include :x
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
context 'when copied JWS is modified' do
|
147
|
-
before do
|
148
|
-
@jws.header[:x] = :x
|
149
|
-
@jws[:obj][:x] = :x
|
150
|
-
end
|
151
|
-
|
152
|
-
describe 'original JWT' do
|
153
|
-
it 'should be affected as shallow copy, but not as a simple reference' do
|
154
|
-
@jwt.header.should_not include :x
|
155
|
-
@jwt[:obj].should include :x
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
describe '#encrypt' do
|
163
|
-
let(:shared_key) { SecureRandom.hex 16 } # default shared key is too short
|
164
|
-
|
165
|
-
it 'should encryptable without signing' do
|
166
|
-
jwt.encrypt(public_key).should be_a JSON::JWE
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'should encryptable after signed' do
|
170
|
-
jwt.sign(shared_key).encrypt(public_key).should be_a JSON::JWE
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'should accept optional algorithm' do
|
174
|
-
jwt.encrypt(shared_key, :dir).should be_a JSON::JWE
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'should accept optional algorithm and encryption method' do
|
178
|
-
jwt.encrypt(SecureRandom.hex(32), :dir, :'A256CBC-HS512').should be_a JSON::JWE
|
179
|
-
end
|
180
|
-
|
181
|
-
context 'when non-JWK key is given' do
|
182
|
-
let(:key) { shared_key }
|
183
|
-
it 'should not set kid header automatically' do
|
184
|
-
jwe = jwt.encrypt(key, :dir)
|
185
|
-
jwe.kid.should be_blank
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
context 'when JWK is given' do
|
190
|
-
let(:key) { JSON::JWK.new shared_key }
|
191
|
-
it 'should set kid header automatically' do
|
192
|
-
jwe = jwt.encrypt(key, :dir)
|
193
|
-
jwt.kid.should be_blank
|
194
|
-
jwe.kid.should == key[:kid]
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
describe '.decode' do
|
200
|
-
context 'when not signed nor encrypted' do
|
201
|
-
context 'no signature given' do
|
202
|
-
it do
|
203
|
-
JSON::JWT.decode(no_signed).should == jwt
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
context 'when signed' do
|
209
|
-
context 'when no secret/key given' do
|
210
|
-
it 'should do verification' do
|
211
|
-
expect do
|
212
|
-
JSON::JWT.decode jws.to_s
|
213
|
-
end.to raise_error JSON::JWT::VerificationFailed
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
context 'when secret/key given' do
|
218
|
-
it 'should do verification' do
|
219
|
-
expect do
|
220
|
-
JSON::JWT.decode jws.to_s, 'secret'
|
221
|
-
end.to raise_error JSON::JWT::VerificationFailed
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
context 'when alg header malformed' do
|
226
|
-
context 'from alg=HS256' do
|
227
|
-
context 'to alg=none' do
|
228
|
-
let(:malformed_jwt_string) do
|
229
|
-
header, payload, signature = jws.to_s.split('.')
|
230
|
-
malformed_header = {alg: :none}.to_json
|
231
|
-
[
|
232
|
-
Base64.urlsafe_encode64(malformed_header, padding: false),
|
233
|
-
payload,
|
234
|
-
''
|
235
|
-
].join('.')
|
236
|
-
end
|
237
|
-
|
238
|
-
it do
|
239
|
-
expect do
|
240
|
-
JSON::JWT.decode malformed_jwt_string, 'secret'
|
241
|
-
end.to raise_error JSON::JWT::VerificationFailed
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
context 'from alg=RS256' do
|
247
|
-
let(:jws) do
|
248
|
-
jwt.sign private_key, :RS256
|
249
|
-
end
|
250
|
-
|
251
|
-
context 'to alg=none' do
|
252
|
-
let(:malformed_jwt_string) do
|
253
|
-
header, payload, signature = jws.to_s.split('.')
|
254
|
-
malformed_header = {alg: :none}.to_json
|
255
|
-
[
|
256
|
-
Base64.urlsafe_encode64(malformed_header, padding: false),
|
257
|
-
payload,
|
258
|
-
''
|
259
|
-
].join('.')
|
260
|
-
end
|
261
|
-
|
262
|
-
it do
|
263
|
-
expect do
|
264
|
-
JSON::JWT.decode malformed_jwt_string, public_key
|
265
|
-
end.to raise_error JSON::JWT::UnexpectedAlgorithm
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
context 'to alg=HS256' do
|
270
|
-
let(:malformed_jwt_string) do
|
271
|
-
header, payload, signature = jws.to_s.split('.')
|
272
|
-
malformed_header = {alg: :HS256}.to_json
|
273
|
-
malformed_signature = OpenSSL::HMAC.digest(
|
274
|
-
OpenSSL::Digest.new('SHA256'),
|
275
|
-
public_key.to_s,
|
276
|
-
[Base64.urlsafe_encode64(malformed_header, padding: false), payload].join('.')
|
277
|
-
)
|
278
|
-
[
|
279
|
-
Base64.urlsafe_encode64(malformed_header, padding: false),
|
280
|
-
payload,
|
281
|
-
Base64.urlsafe_encode64(malformed_signature, padding: false)
|
282
|
-
].join('.')
|
283
|
-
end
|
284
|
-
|
285
|
-
it do
|
286
|
-
expect do
|
287
|
-
JSON::JWT.decode malformed_jwt_string, public_key
|
288
|
-
end.to raise_error JSON::JWS::UnexpectedAlgorithm
|
289
|
-
end
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
context 'from alg=PS512' do
|
294
|
-
let(:jws) do
|
295
|
-
jwt.sign private_key, :PS512
|
296
|
-
end
|
297
|
-
|
298
|
-
if pss_supported?
|
299
|
-
context 'to alg=PS256' do
|
300
|
-
let(:malformed_jwt_string) do
|
301
|
-
header, payload, signature = jws.to_s.split('.')
|
302
|
-
malformed_header = {alg: :PS256}.to_json
|
303
|
-
digest = OpenSSL::Digest.new('SHA256')
|
304
|
-
malformed_signature = private_key.sign_pss(
|
305
|
-
digest,
|
306
|
-
[Base64.urlsafe_encode64(malformed_header, padding: false), payload].join('.'),
|
307
|
-
salt_length: :digest,
|
308
|
-
mgf1_hash: digest
|
309
|
-
)
|
310
|
-
[
|
311
|
-
Base64.urlsafe_encode64(malformed_header, padding: false),
|
312
|
-
payload,
|
313
|
-
Base64.urlsafe_encode64(malformed_signature, padding: false)
|
314
|
-
].join('.')
|
315
|
-
end
|
316
|
-
|
317
|
-
context 'when verification algorithm is specified' do
|
318
|
-
it do
|
319
|
-
expect do
|
320
|
-
JSON::JWT.decode malformed_jwt_string, public_key, :PS512
|
321
|
-
end.to raise_error JSON::JWS::UnexpectedAlgorithm, 'Unexpected alg header'
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
context 'otherwise' do
|
326
|
-
it do
|
327
|
-
expect do
|
328
|
-
JSON::JWT.decode malformed_jwt_string, public_key
|
329
|
-
end.not_to raise_error
|
330
|
-
end
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
context 'to alg=RS516' do
|
335
|
-
let(:malformed_jwt_string) do
|
336
|
-
header, payload, signature = jws.to_s.split('.')
|
337
|
-
malformed_header = {alg: :RS512}.to_json
|
338
|
-
malformed_signature = private_key.sign(
|
339
|
-
OpenSSL::Digest.new('SHA512'),
|
340
|
-
[Base64.urlsafe_encode64(malformed_header, padding: false), payload].join('.')
|
341
|
-
)
|
342
|
-
[
|
343
|
-
Base64.urlsafe_encode64(malformed_header, padding: false),
|
344
|
-
payload,
|
345
|
-
Base64.urlsafe_encode64(malformed_signature, padding: false)
|
346
|
-
].join('.')
|
347
|
-
end
|
348
|
-
|
349
|
-
context 'when verification algorithm is specified' do
|
350
|
-
it do
|
351
|
-
expect do
|
352
|
-
JSON::JWT.decode malformed_jwt_string, public_key, :PS512
|
353
|
-
end.to raise_error JSON::JWS::UnexpectedAlgorithm, 'Unexpected alg header'
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
context 'otherwise' do
|
358
|
-
it do
|
359
|
-
expect do
|
360
|
-
JSON::JWT.decode malformed_jwt_string, public_key
|
361
|
-
end.not_to raise_error
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
365
|
-
else
|
366
|
-
skip 'RSA PSS not supported'
|
367
|
-
it do
|
368
|
-
expect { jws }.to raise_error 'PS512 isn\'t supported. OpenSSL gem v2.1.0+ is required to use PS512.'
|
369
|
-
end
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
context 'when :skip_verification given as secret/key' do
|
375
|
-
it 'should skip verification' do
|
376
|
-
expect do
|
377
|
-
jwt = JSON::JWT.decode jws.to_s, :skip_verification
|
378
|
-
jwt.header.should == {'alg' => 'HS256', 'typ' => 'JWT'}
|
379
|
-
end.not_to raise_error
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
context 'when JSON Serialization given' do
|
384
|
-
let(:signed) { JSON::JWT.new(claims).sign('secret') }
|
385
|
-
|
386
|
-
shared_examples_for :json_serialization_parser do
|
387
|
-
context 'when proper secret given' do
|
388
|
-
it { JSON::JWT.decode(serialized, 'secret').should == signed }
|
389
|
-
end
|
390
|
-
|
391
|
-
context 'when verification skipped' do
|
392
|
-
it { JSON::JWT.decode(serialized, :skip_verification).should == signed }
|
393
|
-
end
|
394
|
-
|
395
|
-
context 'when wrong secret given' do
|
396
|
-
it do
|
397
|
-
expect do
|
398
|
-
JSON::JWT.decode serialized, 'wrong'
|
399
|
-
end.to raise_error JSON::JWT::VerificationFailed
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
context 'when general' do
|
405
|
-
let(:serialized) do
|
406
|
-
{
|
407
|
-
payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
|
408
|
-
signatures: [{
|
409
|
-
protected: Base64.urlsafe_encode64(signed.header.to_json, padding: false),
|
410
|
-
signature: Base64.urlsafe_encode64(signed.signature, padding: false)
|
411
|
-
}]
|
412
|
-
}
|
413
|
-
end
|
414
|
-
it_behaves_like :json_serialization_parser
|
415
|
-
end
|
416
|
-
|
417
|
-
context 'when flattened' do
|
418
|
-
let(:serialized) do
|
419
|
-
{
|
420
|
-
protected: Base64.urlsafe_encode64(signed.header.to_json, padding: false),
|
421
|
-
payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
|
422
|
-
signature: Base64.urlsafe_encode64(signed.signature, padding: false)
|
423
|
-
}
|
424
|
-
end
|
425
|
-
it_behaves_like :json_serialization_parser
|
426
|
-
end
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
context 'when encrypted' do
|
431
|
-
let(:input) { jwt.encrypt(public_key).to_s }
|
432
|
-
let(:shared_key) { SecureRandom.hex 16 } # default shared key is too short
|
433
|
-
|
434
|
-
it 'should decryptable' do
|
435
|
-
JSON::JWT.decode(input, private_key).should be_instance_of JSON::JWE
|
436
|
-
end
|
437
|
-
|
438
|
-
context 'when :skip_decryption given as secret/key' do
|
439
|
-
it 'should skip verification' do
|
440
|
-
expect do
|
441
|
-
jwe = JSON::JWT.decode input, :skip_decryption
|
442
|
-
jwe.should be_instance_of JSON::JWE
|
443
|
-
jwe.header.should == {'alg' => 'RSA1_5', 'enc' => 'A128CBC-HS256'}
|
444
|
-
end.not_to raise_error
|
445
|
-
end
|
446
|
-
end
|
447
|
-
|
448
|
-
context 'when alg & enc is specified' do
|
449
|
-
context 'when expected' do
|
450
|
-
it do
|
451
|
-
expect do
|
452
|
-
JSON::JWT.decode(input, private_key, 'RSA1_5', 'A128CBC-HS256')
|
453
|
-
end.not_to raise_error
|
454
|
-
end
|
455
|
-
end
|
456
|
-
|
457
|
-
context 'when alg is unexpected' do
|
458
|
-
it do
|
459
|
-
expect do
|
460
|
-
JSON::JWT.decode(input, private_key, 'dir', 'A128CBC-HS256')
|
461
|
-
end.to raise_error JSON::JWE::UnexpectedAlgorithm, 'Unexpected alg header'
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
context 'when enc is unexpected' do
|
466
|
-
it do
|
467
|
-
expect do
|
468
|
-
JSON::JWT.decode(input, private_key, 'RSA1_5', 'A128GCM')
|
469
|
-
end.to raise_error JSON::JWE::UnexpectedAlgorithm, 'Unexpected enc header'
|
470
|
-
end
|
471
|
-
end
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
context 'when JSON parse failed' do
|
476
|
-
it do
|
477
|
-
expect do
|
478
|
-
JSON::JWT.decode('header.payload.signature')
|
479
|
-
end.to raise_error JSON::JWT::InvalidFormat
|
480
|
-
end
|
481
|
-
end
|
482
|
-
|
483
|
-
context 'when unexpected format' do
|
484
|
-
context 'when too few dots' do
|
485
|
-
it do
|
486
|
-
expect do
|
487
|
-
JSON::JWT.decode 'header'
|
488
|
-
end.to raise_error JSON::JWT::InvalidFormat
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
|
-
context 'when too many dots' do
|
493
|
-
it do
|
494
|
-
expect do
|
495
|
-
JSON::JWT.decode 'header.payload.signature.too.many.dots'
|
496
|
-
end.to raise_error JSON::JWT::InvalidFormat
|
497
|
-
end
|
498
|
-
end
|
499
|
-
end
|
500
|
-
end
|
501
|
-
|
502
|
-
describe '.pretty_generate' do
|
503
|
-
subject { JSON::JWT.pretty_generate jws.to_s }
|
504
|
-
its(:size) { should == 2 }
|
505
|
-
its(:first) do
|
506
|
-
should == <<~HEADER.chop
|
507
|
-
{
|
508
|
-
"typ": "JWT",
|
509
|
-
"alg": "HS256"
|
510
|
-
}
|
511
|
-
HEADER
|
512
|
-
end
|
513
|
-
its(:last) do
|
514
|
-
should == <<~HEADER.chop
|
515
|
-
{
|
516
|
-
"iss": "joe",
|
517
|
-
"exp": 1300819380,
|
518
|
-
"http://example.com/is_root": true
|
519
|
-
}
|
520
|
-
HEADER
|
521
|
-
end
|
522
|
-
end
|
523
|
-
end
|