jwt 1.5.6 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +74 -0
  3. data/.gitignore +1 -1
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +95 -0
  6. data/.rubocop_todo.yml +191 -0
  7. data/.sourcelevel.yml +18 -0
  8. data/AUTHORS +101 -0
  9. data/Appraisals +10 -0
  10. data/CHANGELOG.md +349 -8
  11. data/Gemfile +2 -1
  12. data/README.md +225 -68
  13. data/Rakefile +4 -1
  14. data/lib/jwt.rb +14 -176
  15. data/lib/jwt/algos.rb +44 -0
  16. data/lib/jwt/algos/ecdsa.rb +35 -0
  17. data/lib/jwt/algos/eddsa.rb +23 -0
  18. data/lib/jwt/algos/hmac.rb +34 -0
  19. data/lib/jwt/algos/none.rb +15 -0
  20. data/lib/jwt/algos/ps.rb +43 -0
  21. data/lib/jwt/algos/rsa.rb +19 -0
  22. data/lib/jwt/algos/unsupported.rb +17 -0
  23. data/lib/jwt/base64.rb +19 -0
  24. data/lib/jwt/claims_validator.rb +35 -0
  25. data/lib/jwt/decode.rb +83 -31
  26. data/lib/jwt/default_options.rb +15 -0
  27. data/lib/jwt/encode.rb +69 -0
  28. data/lib/jwt/error.rb +6 -0
  29. data/lib/jwt/json.rb +10 -9
  30. data/lib/jwt/jwk.rb +51 -0
  31. data/lib/jwt/jwk/ec.rb +150 -0
  32. data/lib/jwt/jwk/hmac.rb +58 -0
  33. data/lib/jwt/jwk/key_base.rb +18 -0
  34. data/lib/jwt/jwk/key_finder.rb +62 -0
  35. data/lib/jwt/jwk/rsa.rb +115 -0
  36. data/lib/jwt/security_utils.rb +57 -0
  37. data/lib/jwt/signature.rb +39 -0
  38. data/lib/jwt/verify.rb +45 -53
  39. data/lib/jwt/version.rb +3 -3
  40. data/ruby-jwt.gemspec +6 -8
  41. metadata +39 -95
  42. data/.codeclimate.yml +0 -20
  43. data/.travis.yml +0 -13
  44. data/Manifest +0 -8
  45. data/spec/fixtures/certs/ec256-private.pem +0 -8
  46. data/spec/fixtures/certs/ec256-public.pem +0 -4
  47. data/spec/fixtures/certs/ec256-wrong-private.pem +0 -8
  48. data/spec/fixtures/certs/ec256-wrong-public.pem +0 -4
  49. data/spec/fixtures/certs/ec384-private.pem +0 -9
  50. data/spec/fixtures/certs/ec384-public.pem +0 -5
  51. data/spec/fixtures/certs/ec384-wrong-private.pem +0 -9
  52. data/spec/fixtures/certs/ec384-wrong-public.pem +0 -5
  53. data/spec/fixtures/certs/ec512-private.pem +0 -10
  54. data/spec/fixtures/certs/ec512-public.pem +0 -6
  55. data/spec/fixtures/certs/ec512-wrong-private.pem +0 -10
  56. data/spec/fixtures/certs/ec512-wrong-public.pem +0 -6
  57. data/spec/fixtures/certs/rsa-1024-private.pem +0 -15
  58. data/spec/fixtures/certs/rsa-1024-public.pem +0 -6
  59. data/spec/fixtures/certs/rsa-2048-private.pem +0 -27
  60. data/spec/fixtures/certs/rsa-2048-public.pem +0 -9
  61. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +0 -27
  62. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +0 -9
  63. data/spec/fixtures/certs/rsa-4096-private.pem +0 -51
  64. data/spec/fixtures/certs/rsa-4096-public.pem +0 -14
  65. data/spec/integration/readme_examples_spec.rb +0 -190
  66. data/spec/jwt/verify_spec.rb +0 -197
  67. data/spec/jwt_spec.rb +0 -240
  68. data/spec/spec_helper.rb +0 -31
@@ -1,9 +0,0 @@
1
- -----BEGIN PUBLIC KEY-----
2
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4GzZTLU48c4WbyvHi+QK
3
- rB71x+T0eq5hqDbQqnlYjhD1Ika7io1iplsdJWJuyxfYbUkb2Ol0fj4koZ/GS6lg
4
- CZr4+8UHbr1qf0Eu5HZSpszs2YxY8U5RHnrpw67co7hlgAR9HbyNf5XIYgLV9ldH
5
- H/eazwnc3F/hgNsV0xjScVilejgocJ4zcsyymvW8t42lteM7bI867ZuJhGop/V+Y
6
- 0HFyrMsPoQyLuCUpr6ulOfrkr7ZOdhAIG8r1HcjOp/AUjM15vfXcbUZjkM/Vloif
7
- X1YitU3upMGJ8/DpFGffMOImrn5r6BT494V8rRyN2qvQoAkLJpqZ0avLxwiR2lgV
8
- QQIDAQAB
9
- -----END PUBLIC KEY-----
@@ -1,27 +0,0 @@
1
- -----BEGIN RSA PRIVATE KEY-----
2
- MIIEpAIBAAKCAQEAzHAVGaW9j4l3/b4ngcjjoIoIcnsQEWOMqErb5VhLZMGIq1gE
3
- O5qxPDAwooKsNotzcAOB3ZyLn7p5D+dmOrNUYkYWgYITNGeSifrnVqQugd5Fh1L8
4
- K7zOGltUo2UtjbN4uJ56tzxBMZp2wejs2/Qu0eu0xZK3To+YkDcWOk92rmNgmUSQ
5
- C/kNyIOj+yBvOo3wTk6HvbhoIarCgJ6Lay1v/hMLyQLzwRY/Qfty1FTIDyTv2dch
6
- 47FsfkZ1KAL+MbUnHuCBPzGxRjXa8Iy9Z7YGxrYasUt1b0um64bscxoIiCu8yLL8
7
- jlg01Rwrjr/MTwKRhwXlMp8B7HTonwtaG6arJwIDAQABAoIBAGFR4dmJusl/qW1T
8
- fj8cQLAFxaupxaZhe24J5NAyzgEy2Dqo9ariIwkB78UM66ozjEqAgOvcP+NTw5m8
9
- kD/VapA1yTTxlO7XdzzUAhiOo80S4IphCMZRZNPLMmluGtdf3lIUr1pXBrn0TCBX
10
- H5o9jaREzpNXGof9d6T/dEdh2J9+uE/p1xE5GSxQfaPheZzCG7636La/DcArg/UR
11
- +TusPqp62BEmk96pE/KKJRmEeH+WnPfSh6sMpLxi3hkEU7AynpliGT6Z6xV4csBI
12
- S/rdpkcj5DWpbnQzkwdrnL2Q+POEq/vlx5/NlezvtQPNLvQWDyY4yBCoMKGb3EbX
13
- xrxP7MECgYEA/kwe4P0Mqk+087IyhjDBGPfcMt8gfYc9nzNfIYSWdSwuSag/hqHq
14
- I4GwHQzUV9ix3iM6w5hin10yAzWxCYZg9hquV+lSvNNpGB76FX6oOqwuAhyQMRwv
15
- eW+VUyfFXeJugwL5JuIaNTvwPpQVDHYtELLifie+uzJ5HC6dhg/XchcCgYEAzc5/
16
- +IXjOlExd/mBgFk/5Y87ifA0ZOgbaJXifYgU0aNSgz1piHxU3n2p4jJ9lSdwwCl2
17
- Fb5EN7666t20PL5QcXJ5ZdaTRLzRlYiqTWzfYHBgttbB1Jl3Ed9GsKuzRgaRqGFC
18
- ANJSqZlKG0NZ3keRtuKdFwq+IVOnsQr9g0TZiXECgYEAqUgtCiMKCloTIGMQpSnR
19
- cXiWWjsUmturls4Q1vQ3YHrvuVLKLyqb/dT4Uu5WcMAs765OESThCit0/pQAbVHK
20
- PCpYwubskAzAGjGM00BEZwJ1gixXhIm5xMIWCowgI7Z3ULlq+IptXeCvtkjHlksZ
21
- BtO+WLLGkkEwRCV38WWcSzMCgYA/Xxqgl/mD94RYAQgTUWgPc69Nph08BQyLg7ue
22
- E8z1UGkT6FEaqc4oRGGPOSTaTK63PQ0TXOb8k0pTD7l0CtYSWMFwzkXCoLGYbeCi
23
- vqd5tqDRLAe7QxYa9rl5pSUqptMrGeeNATZa6sya4H5Hp5oCyny8n54z/OJh7ZRq
24
- W0TwwQKBgQDDP7ksm2pcqadaVAmODdOlaDHbaEcxp8wN7YVz0lM3UpJth96ukbj7
25
- S39eJhXYWOn6oJQb/lN9fGOYqjg3y6IchGZDp67ATvWYvn/NY0R7mt4K4oHx5TuN
26
- rSQlP3WmOGv8Kemw892uRfW/jZyBEHhsfS213WDttVPn9F635GdNWw==
27
- -----END RSA PRIVATE KEY-----
@@ -1,9 +0,0 @@
1
- -----BEGIN PUBLIC KEY-----
2
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHAVGaW9j4l3/b4ngcjj
3
- oIoIcnsQEWOMqErb5VhLZMGIq1gEO5qxPDAwooKsNotzcAOB3ZyLn7p5D+dmOrNU
4
- YkYWgYITNGeSifrnVqQugd5Fh1L8K7zOGltUo2UtjbN4uJ56tzxBMZp2wejs2/Qu
5
- 0eu0xZK3To+YkDcWOk92rmNgmUSQC/kNyIOj+yBvOo3wTk6HvbhoIarCgJ6Lay1v
6
- /hMLyQLzwRY/Qfty1FTIDyTv2dch47FsfkZ1KAL+MbUnHuCBPzGxRjXa8Iy9Z7YG
7
- xrYasUt1b0um64bscxoIiCu8yLL8jlg01Rwrjr/MTwKRhwXlMp8B7HTonwtaG6ar
8
- JwIDAQAB
9
- -----END PUBLIC KEY-----
@@ -1,51 +0,0 @@
1
- -----BEGIN RSA PRIVATE KEY-----
2
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- EWGbN++jcdV5oJX6fsC66nOmKlntYwCL/pRww+oLsbzF8J3dxeDbKNF9JDsCAwEA
13
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- vNP+DUu8NBzwmi0cKlAiaxt+w90i5DWq1XWPKgi+RVLkaQSJqHoYQVNgEwL/cWxp
25
- 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
- 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
- 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
- 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
- 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
- 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
- 7mYDNng4ZWpypeKaGMAQoNzZiUpF+BDnqbeb/kgYu6sNlh9gRHR79rgAuZQxZ/1B
32
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- eJwhAoIBABO17wkSxyGDjJ/fDfpsE3bDmgRV2KuBHoqqOBvXH26sM7ghXLZKjT4o
41
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
51
- -----END RSA PRIVATE KEY-----
@@ -1,14 +0,0 @@
1
- -----BEGIN PUBLIC KEY-----
2
- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqETmgWBi5rCmb7euJplA
3
- /9xs65+bncc9Yvs5zjyycXSW82JfRuyguGm0OvA2wog24dR4N2kT/87DcGtp5JqJ
4
- WADVFNr+2V2r6i57/OMLruRpn3p2r95dmo0COE+BxPFl7XEBT8JbH57ZtpgcB3/x
5
- kS14nLOWFf96hrXPlXJC+VMVKVZmA8k2LRh42vT5wUf4U0Doy/p7yFNSFFa6Q8ww
6
- e4TBy/z/f+rhFD1w8rxlYjallee/ocm7bjZCwbJGMm7orLViqWfsFX3O35PeoJ5h
7
- /7uJ7iRwvTFERkTdwWP/0BeKBeItBR3YFc2mut+V9W+WKRkMSL6Crc+oVSx3p8aB
8
- 7j9SZFzQiRtes4BYETpX1xl2mgIq5hvsFbLw7ESrlIodiwUMTrSIid2DQ6q80kv1
9
- zXPr4+Id6L0sJLxPCaXnTmNtasSwyedJJYxLjwhHJwtzFAeaq18H3O791YKhjAJ6
10
- YxK3zJ59jTE6Pkvqjq183f2PGHVRvgSN7aCmI6MBUUB5wDP2K8zX2sh40/uPDVSd
11
- 6ei1vl3DpPk+h8iExx6AzbohfqZ+5RUUNx127L3MaQvOVC5TxV+R99gwKW++wzcV
12
- uO3m2KqVUj+K1uYBy3KBCUMBbckpEWGbN++jcdV5oJX6fsC66nOmKlntYwCL/pRw
13
- w+oLsbzF8J3dxeDbKNF9JDsCAwEAAQ==
14
- -----END PUBLIC KEY-----
@@ -1,190 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative '../spec_helper'
3
- require 'jwt'
4
-
5
- describe 'README.md code test' do
6
- context 'algorithm usage' do
7
- let(:payload) { { data: 'test' } }
8
-
9
- it 'NONE' do
10
- token = JWT.encode payload, nil, 'none'
11
- decoded_token = JWT.decode token, nil, false
12
-
13
- expect(token).to eq 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.'
14
- expect(decoded_token).to eq [
15
- { 'data' => 'test' },
16
- { 'typ' => 'JWT', 'alg' => 'none' }
17
- ]
18
- end
19
-
20
- it 'HMAC' do
21
- token = JWT.encode payload, 'my$ecretK3y', 'HS256'
22
- decoded_token = JWT.decode token, 'my$ecretK3y', false
23
-
24
- expect(token).to eq 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.ZxW8go9hz3ETCSfxFxpwSkYg_602gOPKearsf6DsxgY'
25
- expect(decoded_token).to eq [
26
- { 'data' => 'test' },
27
- { 'typ' => 'JWT', 'alg' => 'HS256' }
28
- ]
29
- end
30
-
31
- it 'RSA' do
32
- rsa_private = OpenSSL::PKey::RSA.generate 2048
33
- rsa_public = rsa_private.public_key
34
-
35
- token = JWT.encode payload, rsa_private, 'RS256'
36
- decoded_token = JWT.decode token, rsa_public, true, algorithm: 'RS256'
37
-
38
- expect(decoded_token).to eq [
39
- { 'data' => 'test' },
40
- { 'typ' => 'JWT', 'alg' => 'RS256' }
41
- ]
42
- end
43
-
44
- it 'ECDSA' do
45
- ecdsa_key = OpenSSL::PKey::EC.new 'prime256v1'
46
- ecdsa_key.generate_key
47
- ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key
48
- ecdsa_public.private_key = nil
49
-
50
- token = JWT.encode payload, ecdsa_key, 'ES256'
51
- decoded_token = JWT.decode token, ecdsa_public, true, algorithm: 'ES256'
52
-
53
- expect(decoded_token).to eq [
54
- { 'data' => 'test' },
55
- { 'typ' => 'JWT', 'alg' => 'ES256' }
56
- ]
57
- end
58
- end
59
-
60
- context 'claims' do
61
- let(:hmac_secret) { 'MyP4ssW0rD' }
62
-
63
- context 'exp' do
64
- it 'without leeway' do
65
- exp = Time.now.to_i + 4 * 3600
66
- exp_payload = { data: 'data', exp: exp }
67
-
68
- token = JWT.encode exp_payload, hmac_secret, 'HS256'
69
-
70
- expect do
71
- JWT.decode token, hmac_secret, true, algorithm: 'HS256'
72
- end.not_to raise_error
73
- end
74
-
75
- it 'with leeway' do
76
- exp = Time.now.to_i - 10
77
- leeway = 30 # seconds
78
-
79
- exp_payload = { data: 'data', exp: exp }
80
-
81
- token = JWT.encode exp_payload, hmac_secret, 'HS256'
82
-
83
- expect do
84
- JWT.decode token, hmac_secret, true, leeway: leeway, algorithm: 'HS256'
85
- end.not_to raise_error
86
- end
87
- end
88
-
89
- context 'nbf' do
90
- it 'without leeway' do
91
- nbf = Time.now.to_i - 3600
92
- nbf_payload = { data: 'data', nbf: nbf }
93
- token = JWT.encode nbf_payload, hmac_secret, 'HS256'
94
-
95
- expect do
96
- JWT.decode token, hmac_secret, true, algorithm: 'HS256'
97
- end.not_to raise_error
98
- end
99
-
100
- it 'with leeway' do
101
- nbf = Time.now.to_i + 10
102
- leeway = 30
103
- nbf_payload = { data: 'data', nbf: nbf }
104
- token = JWT.encode nbf_payload, hmac_secret, 'HS256'
105
-
106
- expect do
107
- JWT.decode token, hmac_secret, true, leeway: leeway, algorithm: 'HS256'
108
- end.not_to raise_error
109
- end
110
- end
111
-
112
- it 'iss' do
113
- iss = 'My Awesome Company Inc. or https://my.awesome.website/'
114
- iss_payload = { data: 'data', iss: iss }
115
-
116
- token = JWT.encode iss_payload, hmac_secret, 'HS256'
117
-
118
- expect do
119
- JWT.decode token, hmac_secret, true, iss: iss, algorithm: 'HS256'
120
- end.not_to raise_error
121
- end
122
-
123
- context 'aud' do
124
- it 'array' do
125
- aud = %w(Young Old)
126
- aud_payload = { data: 'data', aud: aud }
127
-
128
- token = JWT.encode aud_payload, hmac_secret, 'HS256'
129
-
130
- expect do
131
- JWT.decode token, hmac_secret, true, aud: %w(Old Young), verify_aud: true, algorithm: 'HS256'
132
- end.not_to raise_error
133
- end
134
-
135
- it 'string' do
136
- expect do
137
- end.not_to raise_error
138
- end
139
- end
140
-
141
- it 'jti' do
142
- iat = Time.now.to_i
143
- hmac_secret = 'test'
144
- jti_raw = [hmac_secret, iat].join(':').to_s
145
- jti = Digest::MD5.hexdigest(jti_raw)
146
- jti_payload = { data: 'data', iat: iat, jti: jti }
147
-
148
- token = JWT.encode jti_payload, hmac_secret, 'HS256'
149
-
150
- expect do
151
- JWT.decode token, hmac_secret, true, verify_jti: true, algorithm: 'HS256'
152
- end.not_to raise_error
153
- end
154
-
155
- context 'iat' do
156
- it 'without leeway' do
157
- iat = Time.now.to_i
158
- iat_payload = { data: 'data', iat: iat }
159
-
160
- token = JWT.encode iat_payload, hmac_secret, 'HS256'
161
-
162
- expect do
163
- JWT.decode token, hmac_secret, true, verify_iat: true, algorithm: 'HS256'
164
- end.not_to raise_error
165
- end
166
-
167
- it 'with leeway' do
168
- iat = Time.now.to_i - 7
169
- iat_payload = { data: 'data', iat: iat, leeway: 10 }
170
-
171
- token = JWT.encode iat_payload, hmac_secret, 'HS256'
172
-
173
- expect do
174
- JWT.decode token, hmac_secret, true, verify_iat: true, algorithm: 'HS256'
175
- end.not_to raise_error
176
- end
177
- end
178
-
179
- it 'sub' do
180
- sub = 'Subject'
181
- sub_payload = { data: 'data', sub: sub }
182
-
183
- token = JWT.encode sub_payload, hmac_secret, 'HS256'
184
-
185
- expect do
186
- JWT.decode token, hmac_secret, true, 'sub' => sub, :verify_sub => true, :algorithm => 'HS256'
187
- end.not_to raise_error
188
- end
189
- end
190
- end
@@ -1,197 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'spec_helper'
3
- require 'jwt/verify'
4
-
5
- module JWT
6
- RSpec.describe Verify do
7
- let(:base_payload) { { 'user_id' => 'some@user.tld' } }
8
- let(:options) { { leeway: 0 } }
9
-
10
- context '.verify_aud(payload, options)' do
11
- let(:scalar_aud) { 'ruby-jwt-audience' }
12
- let(:array_aud) { %w(ruby-jwt-aud test-aud ruby-ruby-ruby) }
13
- let(:scalar_payload) { base_payload.merge('aud' => scalar_aud) }
14
- let(:array_payload) { base_payload.merge('aud' => array_aud) }
15
-
16
- it 'must raise JWT::InvalidAudError when the singular audience does not match' do
17
- expect do
18
- Verify.verify_aud(scalar_payload, options.merge(aud: 'no-match'))
19
- end.to raise_error JWT::InvalidAudError
20
- end
21
-
22
- it 'must raise JWT::InvalidAudError when the payload has an array and none match the supplied value' do
23
- expect do
24
- Verify.verify_aud(array_payload, options.merge(aud: 'no-match'))
25
- end.to raise_error JWT::InvalidAudError
26
- end
27
-
28
- it 'must raise JWT::InvalidAudError when the singular audience does not match and the options aud key is a string' do
29
- expect do
30
- Verify.verify_aud(scalar_payload, options.merge('aud' => 'no-match'))
31
- end.to raise_error JWT::InvalidAudError
32
- end
33
-
34
- it 'must allow a matching singular audience to pass' do
35
- Verify.verify_aud(scalar_payload, options.merge(aud: scalar_aud))
36
- end
37
-
38
- it 'must allow a matching audence to pass when the options key is a string' do
39
- Verify.verify_aud(scalar_payload, options.merge('aud' => scalar_aud))
40
- end
41
-
42
- it 'must allow an array with any value matching the one in the options' do
43
- Verify.verify_aud(array_payload, options.merge(aud: array_aud.first))
44
- end
45
-
46
- it 'must allow an array with any value matching the one in the options with a string options key' do
47
- Verify.verify_aud(array_payload, options.merge('aud' => array_aud.first))
48
- end
49
-
50
- it 'should allow strings or symbolds in options array' do
51
- options['aud'] = [
52
- 'ruby-jwt-aud',
53
- 'test-aud',
54
- 'ruby-ruby-ruby',
55
- :test
56
- ]
57
-
58
- array_payload['aud'].push('test')
59
-
60
- Verify.verify_aud(array_payload, options)
61
- end
62
- end
63
-
64
- context '.verify_expiration(payload, options)' do
65
- let(:leeway) { 10 }
66
- let(:payload) { base_payload.merge('exp' => (Time.now.to_i - 5)) }
67
-
68
- it 'must raise JWT::ExpiredSignature when the token has expired' do
69
- expect do
70
- Verify.verify_expiration(payload, options)
71
- end.to raise_error JWT::ExpiredSignature
72
- end
73
-
74
- it 'must allow some leeway in the expiration when configured' do
75
- Verify.verify_expiration(payload, options.merge(leeway: 10))
76
- end
77
-
78
- it 'must be expired if the exp claim equals the current time' do
79
- payload['exp'] = Time.now.to_i
80
-
81
- expect do
82
- Verify.verify_expiration(payload, options)
83
- end.to raise_error JWT::ExpiredSignature
84
- end
85
- end
86
-
87
- context '.verify_iat(payload, options)' do
88
- let(:iat) { Time.now.to_f }
89
- let(:payload) { base_payload.merge('iat' => iat) }
90
-
91
- it 'must allow a valid iat' do
92
- Verify.verify_iat(payload, options)
93
- end
94
-
95
- it 'must allow configured leeway' do
96
- Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(leeway: 70))
97
- end
98
-
99
- it 'must properly handle integer times' do
100
- Verify.verify_iat(payload.merge('iat' => Time.now.to_i), options)
101
- end
102
-
103
- it 'must raise JWT::InvalidIatError when the iat value is not Numeric' do
104
- expect do
105
- Verify.verify_iat(payload.merge('iat' => 'not a number'), options)
106
- end.to raise_error JWT::InvalidIatError
107
- end
108
-
109
- it 'must raise JWT::InvalidIatError when the iat value is in the future' do
110
- expect do
111
- Verify.verify_iat(payload.merge('iat' => (iat + 120)), options)
112
- end.to raise_error JWT::InvalidIatError
113
- end
114
- end
115
-
116
- context '.verify_iss(payload, options)' do
117
- let(:iss) { 'ruby-jwt-gem' }
118
- let(:payload) { base_payload.merge('iss' => iss) }
119
-
120
- let(:invalid_token) { JWT.encode base_payload, payload[:secret] }
121
-
122
- it 'must raise JWT::InvalidIssuerError when the configured issuer does not match the payload issuer' do
123
- expect do
124
- Verify.verify_iss(payload, options.merge(iss: 'mismatched-issuer'))
125
- end.to raise_error JWT::InvalidIssuerError
126
- end
127
-
128
- it 'must raise JWT::InvalidIssuerError when the payload does not include an issuer' do
129
- expect do
130
- Verify.verify_iss(base_payload, options.merge(iss: iss))
131
- end.to raise_error(JWT::InvalidIssuerError, /received <none>/)
132
- end
133
-
134
- it 'must allow a matching issuer to pass' do
135
- Verify.verify_iss(payload, options.merge(iss: iss))
136
- end
137
- end
138
-
139
- context '.verify_jti(payload, options)' do
140
- let(:payload) { base_payload.merge('jti' => 'some-random-uuid-or-whatever') }
141
-
142
- it 'must allow any jti when the verfy_jti key in the options is truthy but not a proc' do
143
- Verify.verify_jti(payload, options.merge(verify_jti: true))
144
- end
145
-
146
- it 'must raise JWT::InvalidJtiError when the jti is missing' do
147
- expect do
148
- Verify.verify_jti(base_payload, options)
149
- end.to raise_error JWT::InvalidJtiError, /missing/i
150
- end
151
-
152
- it 'must raise JWT::InvalidJtiError when the jti is an empty string' do
153
- expect do
154
- Verify.verify_jti(base_payload.merge('jti' => ' '), options)
155
- end.to raise_error JWT::InvalidJtiError, /missing/i
156
- end
157
-
158
- it 'must raise JWT::InvalidJtiError when verify_jti proc returns false' do
159
- expect do
160
- Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { false }))
161
- end.to raise_error JWT::InvalidJtiError, /invalid/i
162
- end
163
-
164
- it 'true proc should not raise JWT::InvalidJtiError' do
165
- Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { true }))
166
- end
167
- end
168
-
169
- context '.verify_not_before(payload, options)' do
170
- let(:payload) { base_payload.merge('nbf' => (Time.now.to_i + 5)) }
171
-
172
- it 'must raise JWT::ImmatureSignature when the nbf in the payload is in the future' do
173
- expect do
174
- Verify.verify_not_before(payload, options)
175
- end.to raise_error JWT::ImmatureSignature
176
- end
177
-
178
- it 'must allow some leeway in the token age when configured' do
179
- Verify.verify_not_before(payload, options.merge(leeway: 10))
180
- end
181
- end
182
-
183
- context '.verify_sub(payload, options)' do
184
- let(:sub) { 'ruby jwt subject' }
185
-
186
- it 'must raise JWT::InvalidSubError when the subjects do not match' do
187
- expect do
188
- Verify.verify_sub(base_payload.merge('sub' => 'not-a-match'), options.merge(sub: sub))
189
- end.to raise_error JWT::InvalidSubError
190
- end
191
-
192
- it 'must allow a matching sub' do
193
- Verify.verify_sub(base_payload.merge('sub' => sub), options.merge(sub: sub))
194
- end
195
- end
196
- end
197
- end