jwt 1.5.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +20 -0
  3. data/.ebert.yml +18 -0
  4. data/.gitignore +11 -0
  5. data/.reek.yml +40 -0
  6. data/.rspec +1 -0
  7. data/.rubocop.yml +98 -0
  8. data/.travis.yml +14 -0
  9. data/CHANGELOG.md +476 -0
  10. data/Gemfile +3 -0
  11. data/LICENSE +7 -0
  12. data/Manifest +3 -1
  13. data/README.md +478 -0
  14. data/Rakefile +8 -15
  15. data/lib/jwt/algos/ecdsa.rb +35 -0
  16. data/lib/jwt/algos/eddsa.rb +23 -0
  17. data/lib/jwt/algos/hmac.rb +33 -0
  18. data/lib/jwt/algos/rsa.rb +19 -0
  19. data/lib/jwt/algos/unsupported.rb +16 -0
  20. data/lib/jwt/decode.rb +49 -0
  21. data/lib/jwt/default_options.rb +15 -0
  22. data/lib/jwt/encode.rb +51 -0
  23. data/lib/jwt/error.rb +16 -0
  24. data/lib/jwt/security_utils.rb +51 -0
  25. data/lib/jwt/signature.rb +50 -0
  26. data/lib/jwt/verify.rb +102 -0
  27. data/lib/jwt/version.rb +24 -0
  28. data/lib/jwt.rb +33 -203
  29. data/ruby-jwt.gemspec +31 -0
  30. data/spec/fixtures/certs/ec256-private.pem +8 -0
  31. data/spec/fixtures/certs/ec256-public.pem +4 -0
  32. data/spec/fixtures/certs/ec256-wrong-private.pem +8 -0
  33. data/spec/fixtures/certs/ec256-wrong-public.pem +4 -0
  34. data/spec/fixtures/certs/ec384-private.pem +9 -0
  35. data/spec/fixtures/certs/ec384-public.pem +5 -0
  36. data/spec/fixtures/certs/ec384-wrong-private.pem +9 -0
  37. data/spec/fixtures/certs/ec384-wrong-public.pem +5 -0
  38. data/spec/fixtures/certs/ec512-private.pem +10 -0
  39. data/spec/fixtures/certs/ec512-public.pem +6 -0
  40. data/spec/fixtures/certs/ec512-wrong-private.pem +10 -0
  41. data/spec/fixtures/certs/ec512-wrong-public.pem +6 -0
  42. data/spec/fixtures/certs/rsa-1024-private.pem +15 -0
  43. data/spec/fixtures/certs/rsa-1024-public.pem +6 -0
  44. data/spec/fixtures/certs/rsa-2048-private.pem +27 -0
  45. data/spec/fixtures/certs/rsa-2048-public.pem +9 -0
  46. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +27 -0
  47. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +9 -0
  48. data/spec/fixtures/certs/rsa-4096-private.pem +51 -0
  49. data/spec/fixtures/certs/rsa-4096-public.pem +14 -0
  50. data/spec/integration/readme_examples_spec.rb +202 -0
  51. data/spec/jwt/verify_spec.rb +232 -0
  52. data/spec/jwt_spec.rb +236 -384
  53. data/spec/spec_helper.rb +28 -0
  54. metadata +187 -26
  55. data/jwt.gemspec +0 -34
  56. data/lib/jwt/json.rb +0 -32
  57. data/spec/helper.rb +0 -19
data/spec/jwt_spec.rb CHANGED
@@ -1,463 +1,315 @@
1
- # encoding: utf-8
2
- require 'helper'
1
+ require 'spec_helper'
2
+ require 'jwt'
3
+ require 'jwt/encode'
4
+ require 'jwt/decode'
3
5
 
4
6
  describe JWT do
5
- before do
6
- @payload = { 'foo' => 'bar', 'exp' => Time.now.to_i + 1, 'nbf' => Time.now.to_i - 1 }
7
- end
8
-
9
- it 'encodes and decodes JWTs' do
10
- secret = 'secret'
11
- jwt = JWT.encode(@payload, secret)
12
- decoded_payload = JWT.decode(jwt, secret)
13
- expect(decoded_payload).to include(@payload)
14
- end
15
-
16
- it 'encodes and decodes JWTs for RSA signatures' do
17
- private_key = OpenSSL::PKey::RSA.generate(512)
18
- jwt = JWT.encode(@payload, private_key, 'RS256')
19
- decoded_payload = JWT.decode(jwt, private_key.public_key)
20
- expect(decoded_payload).to include(@payload)
21
- end
22
-
23
- it 'encodes and decodes JWTs for ECDSA P-256 signatures' do
24
- private_key = OpenSSL::PKey::EC.new('prime256v1')
25
- private_key.generate_key
26
- public_key = OpenSSL::PKey::EC.new(private_key)
27
- public_key.private_key = nil
28
- jwt = JWT.encode(@payload, private_key, 'ES256')
29
- decoded_payload = JWT.decode(jwt, public_key)
30
- expect(decoded_payload).to include(@payload)
7
+ let(:payload) { { 'user_id' => 'some@user.tld' } }
8
+
9
+ let :data do
10
+ {
11
+ :secret => 'My$ecretK3y',
12
+ :rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-private.pem'))),
13
+ :rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-public.pem'))),
14
+ :wrong_rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))),
15
+ :wrong_rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))),
16
+ 'ES256_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-private.pem'))),
17
+ 'ES256_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-public.pem'))),
18
+ 'ES384_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-private.pem'))),
19
+ 'ES384_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-public.pem'))),
20
+ 'ES512_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-private.pem'))),
21
+ 'ES512_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-public.pem'))),
22
+ 'ED25519_private' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF'),
23
+ 'ED25519_public' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF').verify_key,
24
+ 'NONE' => 'eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.',
25
+ 'HS256' => 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.kWOVtIOpWcG7JnyJG0qOkTDbOy636XrrQhMm_8JrRQ8',
26
+ 'HS512256' => 'eyJhbGciOiJIUzUxMjI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Ds_4ibvf7z4QOBoKntEjDfthy3WJ-3rKMspTEcHE2bA',
27
+ 'HS384' => 'eyJhbGciOiJIUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.VuV4j4A1HKhWxCNzEcwc9qVF3frrEu-BRLzvYPkbWO0LENRGy5dOiBQ34remM3XH',
28
+ 'HS512' => 'eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.8zNtCBTJIZTHpZ-BkhR-6sZY1K85Nm5YCKqV3AxRdsBJDt_RR-REH2db4T3Y0uQwNknhrCnZGvhNHrvhDwV1kA',
29
+ 'RS256' => 'eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.eSXvWP4GViiwUALj_-qTxU68I1oM0XjgDsCZBBUri2Ghh9d75QkVDoZ_v872GaqunN5A5xcnBK0-cOq-CR6OwibgJWfOt69GNzw5RrOfQ2mz3QI3NYEq080nF69h8BeqkiaXhI24Q51joEgfa9aj5Y-oitLAmtDPYTm7vTcdGufd6AwD3_3jajKBwkh0LPSeMtbe_5EyS94nFoEF9OQuhJYjUmp7agsBVa8FFEjVw5jEgVqkvERSj5hSY4nEiCAomdVxIKBfykyi0d12cgjhI7mBFwWkPku8XIPGZ7N8vpiSLdM68BnUqIK5qR7NAhtvT7iyLFgOqhZNUQ6Ret5VpQ',
30
+ 'RS384' => 'eyJhbGciOiJSUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Sfgk56moPghtsjaP4so6tOy3I553mgwX-5gByMC6dX8lpeWgsxSeAd_K8IyO7u4lwYOL0DSftnqO1HEOuN1AKyBbDvaTXz3u2xNA2x4NYLdW4AZA6ritbYcKLO5BHTXw5ueMbtA1jjGXP0zI_aK2iJTMBmB8SCF88RYBUH01Tyf4PlLj98pGL-v3prZd6kZkIeRJ3326h04hslcB5HQKmgeBk24QNLIoIC-CD329HPjJ7TtGx01lj-ehTBnwVbBGzYFAyoalV5KgvL_MDOfWPr1OYHnR5s_Fm6_3Vg4u6lBljvHOrmv4Nfx7d8HLgbo8CwH4qn1wm6VQCtuDd-uhRg',
31
+ 'RS512' => 'eyJhbGciOiJSUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.LIIAUEuCkGNdpYguOO5LoW4rZ7ED2POJrB0pmEAAchyTdIK4HKh1jcLxc6KyGwZv40njCgub3y72q6vcQTn7oD0zWFCVQRIDW1911Ii2hRNHuigiPUnrnZh1OQ6z65VZRU6GKs8omoBGU9vrClBU0ODqYE16KxYmE_0n4Xw2h3D_L1LF0IAOtDWKBRDa3QHwZRM9sHsHNsBuD5ye9KzDYN1YALXj64LBfA-DoCKfpVAm9NkRPOyzjR2X2C3TomOSJgqWIVHJucudKDDAZyEbO4RA5pI-UFYy1370p9bRajvtDyoBuLDCzoSkMyQ4L2DnLhx5CbWcnD7Cd3GUmnjjTA',
32
+ 'ES256' => '',
33
+ 'ES384' => '',
34
+ 'ES512' => ''
35
+ }
36
+ end
37
+
38
+ after(:each) do
39
+ expect(OpenSSL.errors).to be_empty
31
40
  end
32
41
 
33
- it 'encodes and decodes JWTs for ECDSA P-384 signatures' do
34
- private_key = OpenSSL::PKey::EC.new('secp384r1')
35
- private_key.generate_key
36
- public_key = OpenSSL::PKey::EC.new(private_key)
37
- public_key.private_key = nil
38
- jwt = JWT.encode(@payload, private_key, 'ES384')
39
- decoded_payload = JWT.decode(jwt, public_key)
40
- expect(decoded_payload).to include(@payload)
41
- end
42
+ context 'alg: NONE' do
43
+ let(:alg) { 'none' }
42
44
 
43
- it 'encodes and decodes JWTs for ECDSA P-521 signatures' do
44
- private_key = OpenSSL::PKey::EC.new('secp521r1')
45
- private_key.generate_key
46
- public_key = OpenSSL::PKey::EC.new(private_key)
47
- public_key.private_key = nil
48
- jwt = JWT.encode(@payload, private_key, 'ES512')
49
- decoded_payload = JWT.decode(jwt, public_key)
50
- expect(decoded_payload).to include(@payload)
51
- end
45
+ it 'should generate a valid token' do
46
+ token = JWT.encode payload, nil, alg
52
47
 
53
- it 'encodes and decodes JWTs with custom header fields' do
54
- private_key = OpenSSL::PKey::RSA.generate(512)
55
- jwt = JWT.encode(@payload, private_key, 'RS256', 'kid' => 'default')
56
- decoded_payload = JWT.decode(jwt) do |header|
57
- expect(header['kid']).to eq('default')
58
- private_key.public_key
48
+ expect(token).to eq data['NONE']
59
49
  end
60
- expect(decoded_payload).to include(@payload)
61
- end
62
50
 
63
- it 'raises encode exception when ECDSA algorithm does not match key' do
64
- private_key = OpenSSL::PKey::EC.new('prime256v1')
65
- private_key.generate_key
66
- expect do
67
- JWT.encode(@payload, private_key, 'ES512')
68
- end.to raise_error(JWT::IncorrectAlgorithm, 'payload algorithm is ES512 but ES256 signing key was provided')
69
- end
51
+ it 'should decode a valid token' do
52
+ jwt_payload, header = JWT.decode data['NONE'], nil, false
70
53
 
71
- it 'decodes valid JWTs' do
72
- example_payload = { 'hello' => 'world' }
73
- example_secret = 'secret'
74
- example_jwt = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8'
75
- decoded_payload = JWT.decode(example_jwt, example_secret)
76
- expect(decoded_payload).to include(example_payload)
77
- end
54
+ expect(header['alg']).to eq alg
55
+ expect(jwt_payload).to eq payload
56
+ end
78
57
 
79
- it 'decodes valid ES512 JWTs' do
80
- example_payload = { 'hello' => 'world' }
81
- example_jwt = 'eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.AQx1MqdTni6KuzfOoedg2-7NUiwe-b88SWbdmviz40GTwrM0Mybp1i1tVtmTSQ91oEXGXBdtwsN6yalzP9J-sp2YATX_Tv4h-BednbdSvYxZsYnUoZ--ZUdL10t7g8Yt3y9hdY_diOjIptcha6ajX8yzkDGYG42iSe3f5LywSuD6FO5c'
82
- pubkey_pem = "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAcpkss6wI7PPlxj3t7A1RqMH3nvL4\nL5Tzxze/XeeYZnHqxiX+gle70DlGRMqqOq+PJ6RYX7vK0PJFdiAIXlyPQq0B3KaU\ne86IvFeQSFrJdCc0K8NfiH2G1loIk3fiR+YLqlXk6FAeKtpXJKxR1pCQCAM+vBCs\nmZudf1zCUZ8/4eodlHU=\n-----END PUBLIC KEY-----"
83
- pubkey = OpenSSL::PKey::EC.new pubkey_pem
84
- decoded_payload = JWT.decode(example_jwt, pubkey)
85
- expect(decoded_payload).to include(example_payload)
86
- end
58
+ it 'should display a better error message if payload exp is_a?(Time)' do
59
+ payload['exp'] = Time.now
87
60
 
88
- it 'decodes valid JWTs with iss' do
89
- example_payload = { 'hello' => 'world', 'iss' => 'jwtiss' }
90
- example_secret = 'secret'
91
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
92
- decoded_payload = JWT.decode(example_jwt, example_secret, true, 'iss' => 'jwtiss')
93
- expect(decoded_payload).to include(example_payload)
94
- end
61
+ expect do
62
+ JWT.encode payload, nil, alg
63
+ end.to raise_error JWT::InvalidPayload
64
+ end
95
65
 
96
- context 'issuer claim verifications' do
97
- it 'raises invalid issuer when "iss" claim does not match' do
98
- example_secret = 'secret'
66
+ it 'should display a better error message if payload exp is not an Integer' do
67
+ payload['exp'] = Time.now.to_i.to_s
99
68
 
100
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
101
- expect { JWT.decode(example_jwt, example_secret, true, :verify_iss => true, 'iss' => 'jwt_iss') }.to raise_error(JWT::InvalidIssuerError, /Expected jwt_iss, received jwtiss/)
69
+ expect do
70
+ JWT.encode payload, nil, alg
71
+ end.to raise_error JWT::InvalidPayload
102
72
  end
73
+ end
103
74
 
104
- it 'raises invalid issuer when "iss" claim is missing in payload' do
105
- example_secret = 'secret'
75
+ %w[HS256 HS512256 HS384 HS512].each do |alg|
76
+ context "alg: #{alg}" do
77
+ it 'should generate a valid token' do
78
+ token = JWT.encode payload, data[:secret], alg
106
79
 
107
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIn0.bqxXg9VwcbXKoiWtp-osd0WKPX307RjcN7EuXbdq-CE'
108
- expect { JWT.decode(example_jwt, example_secret, true, :verify_iss => true, 'iss' => 'jwt_iss') }.to raise_error(JWT::InvalidIssuerError, /received <none>/)
109
- end
80
+ expect(token).to eq data[alg]
81
+ end
110
82
 
111
- it 'does not raise invalid issuer when verify_iss is set to false (default option)' do
112
- example_secret = 'secret'
83
+ it 'should decode a valid token' do
84
+ jwt_payload, header = JWT.decode data[alg], data[:secret], true, algorithm: alg
113
85
 
114
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
115
- expect { JWT.decode(example_jwt, example_secret, true, 'iss' => 'jwt_iss') }.not_to raise_error
116
- end
86
+ expect(header['alg']).to eq alg
87
+ expect(jwt_payload).to eq payload
88
+ end
117
89
 
118
- it 'does not raise invalid issuer when correct "iss" is in payload' do
119
- example_secret = 'secret'
90
+ it 'wrong secret should raise JWT::DecodeError' do
91
+ expect do
92
+ JWT.decode data[alg], 'wrong_secret', true, algorithm: alg
93
+ end.to raise_error JWT::VerificationError
94
+ end
120
95
 
121
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0X2lzcyJ9.mwbyRJJZJR1C5lBt8WOLg0ZMuwP9VGDf5HiQtFhd-eA'
122
- expect { JWT.decode(example_jwt, example_secret, true, :verify_iss => true, 'iss' => 'jwt_iss') }.not_to raise_error
96
+ it 'wrong secret and verify = false should not raise JWT::DecodeError' do
97
+ expect do
98
+ JWT.decode data[alg], 'wrong_secret', false
99
+ end.not_to raise_error
100
+ end
123
101
  end
124
102
  end
125
103
 
126
- it 'decodes valid JWTs with iat' do
127
- example_payload = { 'hello' => 'world', 'iat' => 1425917209 }
128
- example_secret = 'secret'
129
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5fQ.m4F-Ugo7aLnLunBBO3BeDidyWMx8T9eoJz6FW2rgQhU'
130
- decoded_payload = JWT.decode(example_jwt, example_secret, true, 'iat' => true)
131
- expect(decoded_payload).to include(example_payload)
132
- end
104
+ %w[RS256 RS384 RS512].each do |alg|
105
+ context "alg: #{alg}" do
106
+ it 'should generate a valid token' do
107
+ token = JWT.encode payload, data[:rsa_private], alg
133
108
 
134
- it 'raises decode exception when iat is invalid' do
135
- # example_payload = {'hello' => 'world', 'iat' => 'abc'}
136
- example_secret = 'secret'
137
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoiMTQyNTkxNzIwOSJ9.Mn_vk61xWjIhbXFqAB0nFmNkDiCmfzUgl_LaCKRT6S8'
138
- expect { JWT.decode(example_jwt, example_secret, true, :verify_iat => true, 'iat' => 1425917209) }.to raise_error(JWT::InvalidIatError)
139
- end
109
+ expect(token).to eq data[alg]
110
+ end
140
111
 
141
- it 'decodes valid JWTs with jti' do
142
- example_payload = { 'hello' => 'world', 'iat' => 1425917209, 'jti' => Digest::MD5.hexdigest('secret:1425917209') }
143
- example_secret = 'secret'
144
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
145
- decoded_payload = JWT.decode(example_jwt, example_secret, true, 'jti' => Digest::MD5.hexdigest('secret:1425917209'))
146
- expect(decoded_payload).to include(example_payload)
147
- end
112
+ it 'should decode a valid token' do
113
+ jwt_payload, header = JWT.decode data[alg], data[:rsa_public], true, algorithm: alg
148
114
 
149
- it 'raises decode exception when jti is invalid' do
150
- # example_payload = {'hello' => 'world', 'iat' => 1425917209, 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
151
- example_secret = 'secret'
152
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
153
- expect { JWT.decode(example_jwt, example_secret, true, :verify_jti => true, 'jti' => Digest::MD5.hexdigest('secret:1425922032')) }.to raise_error(JWT::InvalidJtiError)
154
- # expect{ JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::InvalidJtiError)
155
- end
115
+ expect(header['alg']).to eq alg
116
+ expect(jwt_payload).to eq payload
117
+ end
156
118
 
157
- it 'raises decode exception when jti without iat' do
158
- # example_payload = {'hello' => 'world', 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
159
- example_secret = 'secret'
160
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwianRpIjoiNTVjNzc2ZTIxZjdjYmQ4NzljMDZmYWMwMThkYWM0MDIifQ.n0foJCnCM_-_xUvG_TOmR9mYpL2y0UqZOD_gv33djeE'
161
- expect { JWT.decode(example_jwt, example_secret, true, :verify_jti => true, 'jti' => Digest::MD5.hexdigest('secret:1425922032')) }.to raise_error(JWT::InvalidJtiError)
162
- end
119
+ it 'wrong key should raise JWT::DecodeError' do
120
+ key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
163
121
 
164
- context 'aud claim verifications' do
165
- it 'decodes valid JWTs with aud' do
166
- example_payload = { 'hello' => 'world', 'aud' => 'url:pnd' }
167
- example_payload2 = { 'hello' => 'world', 'aud' => ['url:pnd', 'aud:yes'] }
168
- example_secret = 'secret'
169
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
170
- example_jwt2 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbInVybDpwbmQiLCJhdWQ6eWVzIl19.qNPNcT4X9B5uI91rIwbW2bIPTsp8wbRYW3jkZkrmqbQ'
171
- decoded_payload = JWT.decode(example_jwt, example_secret, true, :verify_aud => true, 'aud' => 'url:pnd')
172
- decoded_payload2 = JWT.decode(example_jwt2, example_secret, true, :verify_aud => true, 'aud' => 'url:pnd')
173
- expect(decoded_payload).to include(example_payload)
174
- expect(decoded_payload2).to include(example_payload2)
175
- end
122
+ expect do
123
+ JWT.decode data[alg], key, true, algorithm: alg
124
+ end.to raise_error JWT::DecodeError
125
+ end
176
126
 
177
- it 'raises deode exception when aud is invalid' do
178
- # example_payload = {'hello' => 'world', 'aud' => 'url:pnd'}
179
- example_secret = 'secret'
180
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
181
- expect { JWT.decode(example_jwt, example_secret, true, :verify_aud => true, 'aud' => 'wrong:aud') }.to raise_error(JWT::InvalidAudError)
182
- end
127
+ it 'wrong key and verify = false should not raise JWT::DecodeError' do
128
+ key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
183
129
 
184
- it 'raises deode exception when aud is missing' do
185
- # JWT.encode('hello' => 'world', 'secret')
186
- example_secret = 'secret'
187
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIn0.bqxXg9VwcbXKoiWtp-osd0WKPX307RjcN7EuXbdq-CE'
188
- expect { JWT.decode(example_jwt, example_secret, true, :verify_aud => true, 'aud' => 'url:pnd') }.to raise_error(JWT::InvalidAudError)
130
+ expect do
131
+ JWT.decode data[alg], key, false
132
+ end.not_to raise_error
133
+ end
189
134
  end
190
135
  end
191
136
 
192
- it 'decodes valid JWTs with sub' do
193
- example_payload = { 'hello' => 'world', 'sub' => 'subject' }
194
- example_secret = 'secret'
195
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwic3ViIjoic3ViamVjdCJ9.QUnNVZm4SPB4vP2zY9m1LoUSOx-5oGXBhj7R89D_UtA'
196
- decoded_payload = JWT.decode(example_jwt, example_secret, true, 'sub' => 'subject')
197
- expect(decoded_payload).to include(example_payload)
198
- end
199
-
200
- it 'raise decode exception when the sub is invalid'
137
+ %w[ED25519].each do |alg|
138
+ context "alg: #{alg}" do
139
+ before(:each) do
140
+ data[alg] = JWT.encode payload, data["#{alg}_private"], alg
141
+ end
201
142
 
202
- it 'raises decode exception when the token is invalid' do
203
- example_secret = 'secret'
204
- # Same as above exmaple with some random bytes replaced
205
- example_jwt = 'eyJhbGciOiAiSFMyNTYiLCAidHiMomlwIjogIkJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8'
206
- expect { JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::DecodeError)
207
- end
143
+ let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }
208
144
 
209
- it 'raises verification exception with wrong hmac key' do
210
- right_secret = 'foo'
211
- bad_secret = 'bar'
212
- jwt_message = JWT.encode(@payload, right_secret, 'HS256')
213
- expect { JWT.decode(jwt_message, bad_secret) }.to raise_error(JWT::VerificationError)
214
- end
145
+ it 'should generate a valid token' do
146
+ jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
215
147
 
216
- it 'raises decode exception when ECDSA algorithm does not match key' do
217
- right_private_key = OpenSSL::PKey::EC.new('prime256v1')
218
- right_private_key.generate_key
219
- right_public_key = OpenSSL::PKey::EC.new(right_private_key)
220
- right_public_key.private_key = nil
221
- bad_private_key = OpenSSL::PKey::EC.new('secp384r1')
222
- bad_private_key.generate_key
223
- bad_public_key = OpenSSL::PKey::EC.new(bad_private_key)
224
- bad_public_key.private_key = nil
225
- jwt = JWT.encode(@payload, right_private_key, 'ES256')
226
- expect do
227
- JWT.decode(jwt, bad_public_key)
228
- end.to raise_error(JWT::IncorrectAlgorithm, 'payload algorithm is ES256 but ES384 verification key was provided')
229
- end
230
-
231
- it 'raises verification exception with wrong rsa key' do
232
- right_private_key = OpenSSL::PKey::RSA.generate(512)
233
- bad_private_key = OpenSSL::PKey::RSA.generate(512)
234
- jwt = JWT.encode(@payload, right_private_key, 'RS256')
235
- expect { JWT.decode(jwt, bad_private_key.public_key) }.to raise_error(JWT::VerificationError)
236
- end
148
+ expect(header['alg']).to eq alg
149
+ expect(jwt_payload).to eq payload
150
+ end
237
151
 
238
- it 'raises verification exception with wrong ECDSA key' do
239
- right_private_key = OpenSSL::PKey::EC.new('prime256v1')
240
- right_private_key.generate_key
241
- bad_private_key = OpenSSL::PKey::EC.new('prime256v1')
242
- bad_private_key.generate_key
243
- bad_public_key = OpenSSL::PKey::EC.new(bad_private_key)
244
- bad_public_key.private_key = nil
245
- jwt = JWT.encode(@payload, right_private_key, 'ES256')
246
- expect { JWT.decode(jwt, bad_public_key) }.to raise_error(JWT::VerificationError)
247
- end
152
+ it 'should decode a valid token' do
153
+ jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
248
154
 
249
- it 'raises decode exception with invalid signature' do
250
- example_secret = 'secret'
251
- example_jwt = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.'
252
- expect { JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::DecodeError)
253
- end
155
+ expect(header['alg']).to eq alg
156
+ expect(jwt_payload).to eq payload
157
+ end
254
158
 
255
- it 'raises decode exception with nonexistent header' do
256
- expect { JWT.decode('..stuff') }.to raise_error(JWT::DecodeError)
257
- end
159
+ it 'wrong key should raise JWT::DecodeError' do
160
+ expect do
161
+ JWT.decode data[alg], wrong_key
162
+ end.to raise_error JWT::DecodeError
163
+ end
258
164
 
259
- it 'raises decode exception with nonexistent payload' do
260
- expect { JWT.decode('eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9..stuff') }.to raise_error(JWT::DecodeError)
165
+ it 'wrong key and verify = false should not raise JWT::DecodeError' do
166
+ expect do
167
+ JWT.decode data[alg], wrong_key, false
168
+ end.not_to raise_error
169
+ end
170
+ end
261
171
  end
172
+ %w[ES256 ES384 ES512].each do |alg|
173
+ context "alg: #{alg}" do
174
+ before(:each) do
175
+ data[alg] = JWT.encode payload, data["#{alg}_private"], alg
176
+ end
262
177
 
263
- it 'raises decode exception with nil jwt' do
264
- expect { JWT.decode(nil) }.to raise_error(JWT::DecodeError)
265
- end
178
+ let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }
266
179
 
267
- it 'allows decoding without key' do
268
- right_secret = 'foo'
269
- bad_secret = 'bar'
270
- jwt = JWT.encode(@payload, right_secret)
271
- decoded_payload = JWT.decode(jwt, bad_secret, false)
272
- expect(decoded_payload).to include(@payload)
273
- end
180
+ it 'should generate a valid token' do
181
+ jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
274
182
 
275
- it 'checks the key when verify is truthy' do
276
- right_secret = 'foo'
277
- bad_secret = 'bar'
278
- jwt = JWT.encode(@payload, right_secret)
279
- verify = 'yes' =~ /^y/i
280
- expect { JWT.decode(jwt, bad_secret, verify) }.to raise_error(JWT::DecodeError)
281
- end
183
+ expect(header['alg']).to eq alg
184
+ expect(jwt_payload).to eq payload
185
+ end
282
186
 
283
- it 'raises exception on unsupported crypto algorithm' do
284
- expect { JWT.encode(@payload, 'secret', 'HS1024') }.to raise_error(NotImplementedError)
285
- end
187
+ it 'should decode a valid token' do
188
+ jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
286
189
 
287
- it 'raises exception when decoded with a different algorithm than it was encoded with' do
288
- jwt = JWT.encode(@payload, 'foo', 'HS384')
289
- expect { JWT.decode(jwt, 'foo', true, :algorithm => 'HS512') }.to raise_error(JWT::IncorrectAlgorithm)
290
- end
190
+ expect(header['alg']).to eq alg
191
+ expect(jwt_payload).to eq payload
192
+ end
291
193
 
292
- it 'does not raise exception when encoded with the expected algorithm' do
293
- jwt = JWT.encode(@payload, 'foo', 'HS512')
294
- JWT.decode(jwt, 'foo', true, :algorithm => 'HS512')
295
- end
194
+ it 'wrong key should raise JWT::DecodeError' do
195
+ expect do
196
+ JWT.decode data[alg], wrong_key
197
+ end.to raise_error JWT::DecodeError
198
+ end
296
199
 
297
- it 'encodes and decodes plaintext JWTs' do
298
- jwt = JWT.encode(@payload, nil, nil)
299
- expect(jwt.split('.').length).to eq(2)
300
- decoded_payload = JWT.decode(jwt, nil, nil)
301
- expect(decoded_payload).to include(@payload)
200
+ it 'wrong key and verify = false should not raise JWT::DecodeError' do
201
+ expect do
202
+ JWT.decode data[alg], wrong_key, false
203
+ end.not_to raise_error
204
+ end
205
+ end
302
206
  end
303
207
 
304
- it 'requires a signature segment when verify is truthy' do
305
- jwt = JWT.encode(@payload, nil, nil)
306
- expect(jwt.split('.').length).to eq(2)
307
- expect { JWT.decode(jwt, nil, true) }.to raise_error(JWT::DecodeError)
308
- end
208
+ context 'Invalid' do
209
+ it 'algorithm should raise NotImplementedError' do
210
+ expect do
211
+ JWT.encode payload, 'secret', 'HS255'
212
+ end.to raise_error NotImplementedError
213
+ end
309
214
 
310
- it 'does not use == to compare digests' do
311
- secret = 'secret'
312
- jwt = JWT.encode(@payload, secret)
313
- crypto_segment = jwt.split('.').last
215
+ it 'ECDSA curve_name should raise JWT::IncorrectAlgorithm' do
216
+ key = OpenSSL::PKey::EC.new 'secp256k1'
217
+ key.generate_key
314
218
 
315
- signature = JWT.base64url_decode(crypto_segment)
316
- expect(signature).not_to receive('==')
317
- expect(JWT).to receive(:base64url_decode).with(crypto_segment).once.and_return(signature)
318
- expect(JWT).to receive(:base64url_decode).at_least(:once).and_call_original
219
+ expect do
220
+ JWT.encode payload, key, 'ES256'
221
+ end.to raise_error JWT::IncorrectAlgorithm
319
222
 
320
- JWT.decode(jwt, secret)
321
- end
223
+ token = JWT.encode payload, data['ES256_private'], 'ES256'
224
+ key.private_key = nil
322
225
 
323
- it 'raises error when expired' do
324
- expired_payload = @payload.clone
325
- expired_payload['exp'] = Time.now.to_i - 1
326
- secret = 'secret'
327
- jwt = JWT.encode(expired_payload, secret)
328
- expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ExpiredSignature)
226
+ expect do
227
+ JWT.decode token, key
228
+ end.to raise_error JWT::IncorrectAlgorithm
229
+ end
329
230
  end
330
231
 
331
- it 'raise ExpiredSignature even when exp claims is a string' do
332
- expired_payload = @payload.clone
333
- expired_payload['exp'] = (Time.now.to_i).to_s
334
- secret = 'secret'
335
- jwt = JWT.encode(expired_payload, secret)
336
- expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ExpiredSignature)
337
- end
232
+ context 'Verify' do
233
+ context 'algorithm' do
234
+ it 'should raise JWT::IncorrectAlgorithm on mismatch' do
235
+ token = JWT.encode payload, data[:secret], 'HS256'
338
236
 
339
- it 'performs normal decode with skipped expiration check' do
340
- expired_payload = @payload.clone
341
- expired_payload['exp'] = Time.now.to_i - 1
342
- secret = 'secret'
343
- jwt = JWT.encode(expired_payload, secret)
344
- decoded_payload = JWT.decode(jwt, secret, true, :verify_expiration => false)
345
- expect(decoded_payload).to include(expired_payload)
346
- end
237
+ expect do
238
+ JWT.decode token, data[:secret], true, algorithm: 'HS384'
239
+ end.to raise_error JWT::IncorrectAlgorithm
347
240
 
348
- it 'performs normal decode using leeway' do
349
- expired_payload = @payload.clone
350
- expired_payload['exp'] = Time.now.to_i - 2
351
- secret = 'secret'
352
- jwt = JWT.encode(expired_payload, secret)
353
- decoded_payload = JWT.decode(jwt, secret, true, :leeway => 3)
354
- expect(decoded_payload).to include(expired_payload)
355
- end
241
+ expect do
242
+ JWT.decode token, data[:secret], true, algorithm: 'HS256'
243
+ end.not_to raise_error
244
+ end
356
245
 
357
- it 'raises error when before nbf' do
358
- immature_payload = @payload.clone
359
- immature_payload['nbf'] = Time.now.to_i + 1
360
- secret = 'secret'
361
- jwt = JWT.encode(immature_payload, secret)
362
- expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ImmatureSignature)
363
- end
246
+ it 'should raise JWT::IncorrectAlgorithm when algorithms array does not contain algorithm' do
247
+ token = JWT.encode payload, data[:secret], 'HS512'
364
248
 
365
- it 'doesnt raise error when after nbf' do
366
- mature_payload = @payload.clone
367
- secret = 'secret'
368
- jwt = JWT.encode(mature_payload, secret)
369
- decoded_payload = JWT.decode(jwt, secret, true, :verify_expiration => false)
370
- expect(decoded_payload).to include(mature_payload)
371
- end
249
+ expect do
250
+ JWT.decode token, data[:secret], true, algorithms: ['HS384']
251
+ end.to raise_error JWT::IncorrectAlgorithm
372
252
 
373
- it 'raise ImmatureSignature even when nbf claim is a string' do
374
- immature_payload = @payload.clone
375
- immature_payload['nbf'] = (Time.now.to_i).to_s
376
- secret = 'secret'
377
- jwt = JWT.encode(immature_payload, secret)
378
- expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ImmatureSignature)
379
- end
253
+ expect do
254
+ JWT.decode token, data[:secret], true, algorithms: ['HS512', 'HS384']
255
+ end.not_to raise_error
256
+ end
380
257
 
381
- it 'performs normal decode with skipped not before check' do
382
- immature_payload = @payload.clone
383
- immature_payload['nbf'] = Time.now.to_i + 2
384
- secret = 'secret'
385
- jwt = JWT.encode(immature_payload, secret)
386
- decoded_payload = JWT.decode(jwt, secret, true, :verify_not_before => false)
387
- expect(decoded_payload).to include(immature_payload)
388
- end
258
+ context 'no algorithm provided' do
259
+ it 'should use the default decode algorithm' do
260
+ token = JWT.encode payload, data[:rsa_public].to_s
389
261
 
390
- it 'performs normal decode using leeway' do
391
- immature_payload = @payload.clone
392
- immature_payload['nbf'] = Time.now.to_i - 2
393
- secret = 'secret'
394
- jwt = JWT.encode(immature_payload, secret)
395
- decoded_payload = JWT.decode(jwt, secret, true, :leeway => 3)
396
- expect(decoded_payload).to include(immature_payload)
397
- end
262
+ jwt_payload, header = JWT.decode token, data[:rsa_public].to_s
398
263
 
399
- describe 'secure comparison' do
400
- it 'returns true if strings are equal' do
401
- expect(JWT.secure_compare('Foo', 'Foo')).to be true
264
+ expect(header['alg']).to eq 'HS256'
265
+ expect(jwt_payload).to eq payload
266
+ end
267
+ end
402
268
  end
403
269
 
404
- it 'returns false if either input is nil or empty' do
405
- [nil, ''].each do |bad|
406
- expect(JWT.secure_compare(bad, 'Foo')).to be false
407
- expect(JWT.secure_compare('Foo', bad)).to be false
270
+ context 'issuer claim' do
271
+ let(:iss) { 'ruby-jwt-gem' }
272
+ let(:invalid_token) { JWT.encode payload, data[:secret] }
273
+
274
+ let :token do
275
+ iss_payload = payload.merge(iss: iss)
276
+ JWT.encode iss_payload, data[:secret]
408
277
  end
409
- end
410
278
 
411
- it 'retuns false if the strings are different' do
412
- expect(JWT.secure_compare('Foo', 'Bar')).to be false
279
+ it 'if verify_iss is set to false (default option) should not raise JWT::InvalidIssuerError' do
280
+ expect do
281
+ JWT.decode token, data[:secret], true, iss: iss, algorithm: 'HS256'
282
+ end.not_to raise_error
283
+ end
413
284
  end
414
285
  end
415
286
 
416
- # no method should leave OpenSSL.errors populated
417
- after do
418
- expect(OpenSSL.errors).to be_empty
287
+ context 'Base64' do
288
+ it 'urlsafe replace + / with - _' do
289
+ allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' }
290
+ expect(JWT::Encode.base64url_encode('foo')).to eq('string-with_non-url-safe_characters_')
291
+ end
419
292
  end
420
293
 
421
- it 'raise exception on invalid signature' do
422
- pubkey = OpenSSL::PKey::RSA.new(<<-PUBKEY)
423
- -----BEGIN PUBLIC KEY-----
424
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCaY7425h964bjaoLeUm
425
- SlZ8sK7VtVk9zHbGmZh2ygGYwfuUf2bmMye2Ofv99yDE/rd4loVIAcu7RVvDRgHq
426
- 3/CZTnIrSvHsiJQsHBNa3d+F1ihPfzURzf1M5k7CFReBj2SBXhDXd57oRfBQj12w
427
- CVhhwP6kGTAWuoppbIIIBfNF2lE/Nvm7lVVYQqL9xOrP/AQ4xRbpQlB8Ll9sO9Or
428
- SvbWhCDa/LMOWxHdmrcJi6XoSg1vnOyCoKbyAoauTt/XqdkHbkDdQ6HFbJieu9il
429
- LDZZNliPhfENuKeC2MCGVXTEu8Cqhy1w6e4axavLlXoYf4laJIZ/e7au8SqDbY0B
430
- xwIDAQAB
431
- -----END PUBLIC KEY-----
432
- PUBKEY
433
- jwt = (
434
- 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY' \
435
- 'XVkIjoiMTA2MDM1Nzg5MTY4OC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSI' \
436
- 'sImNpZCI6IjEwNjAzNTc4OTE2ODguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb' \
437
- '20iLCJpZCI6IjExNjQ1MjgyNDMwOTg1Njc4MjE2MyIsInRva2VuX2hhc2giOiJ' \
438
- '0Z2hEOUo4bjhWME4ydmN3NmVNaWpnIiwiaWF0IjoxMzIwNjcwOTc4LCJleHAiO' \
439
- 'jEzMjA2NzQ4Nzh9.D8x_wirkxDElqKdJBcsIws3Ogesk38okz6MN7zqC7nEAA7' \
440
- 'wcy1PxsROY1fmBvXSer0IQesAqOW-rPOCNReSn-eY8d53ph1x2HAF-AzEi3GOl' \
441
- '6hFycH8wj7Su6JqqyEbIVLxE7q7DkAZGaMPkxbTHs1EhSd5_oaKQ6O4xO3ZnnT4'
442
- )
443
- expect { JWT.decode(jwt, pubkey, true) }.to raise_error(JWT::DecodeError)
294
+ it 'should not verify token even if the payload has claims' do
295
+ head = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9'
296
+ load = 'eyJ1c2VyX2lkIjo1NCwiZXhwIjoxNTA0MzkwODA0fQ'
297
+ sign = 'Skpi6FfYMbZ-DwW9ocyRIosNMdPMAIWRLYxRO68GTQk'
298
+
299
+ expect do
300
+ JWT.decode([head, load, sign].join('.'), '', false)
301
+ end.not_to raise_error
444
302
  end
445
303
 
446
- describe 'urlsafe base64 encoding' do
447
- it 'replaces + and / with - and _' do
448
- allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' }
449
- expect(JWT.base64url_encode('foo')).to eq('string-with_non-url-safe_characters_')
450
- end
304
+ it 'should not raise InvalidPayload exception if payload is an array' do
305
+ expect do
306
+ JWT.encode(['my', 'payload'], 'secret')
307
+ end.not_to raise_error
451
308
  end
452
309
 
453
- describe 'decoded_segments' do
454
- it 'allows access to the decoded header and payload' do
455
- secret = 'secret'
456
- jwt = JWT.encode(@payload, secret)
457
- decoded_segments = JWT.decoded_segments(jwt)
458
- expect(decoded_segments.size).to eq(4)
459
- expect(decoded_segments[0]).to eq('typ' => 'JWT', 'alg' => 'HS256')
460
- expect(decoded_segments[1]).to eq(@payload)
461
- end
310
+ it 'should encode string payloads' do
311
+ expect do
312
+ JWT.encode 'Hello World', 'secret'
313
+ end.not_to raise_error
462
314
  end
463
315
  end