jwt 1.5.2 → 1.5.4

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.
Files changed (41) hide show
  1. checksums.yaml +13 -5
  2. data/.codeclimate.yml +20 -0
  3. data/.gitignore +6 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +2 -0
  6. data/.travis.yml +13 -0
  7. data/Gemfile +4 -0
  8. data/README.md +29 -11
  9. data/Rakefile +1 -18
  10. data/lib/jwt.rb +19 -75
  11. data/lib/jwt/decode.rb +56 -0
  12. data/lib/jwt/error.rb +12 -0
  13. data/lib/jwt/json.rb +9 -25
  14. data/lib/jwt/verify.rb +98 -0
  15. data/lib/jwt/version.rb +23 -0
  16. data/ruby-jwt.gemspec +29 -0
  17. data/spec/fixtures/certs/ec256-private.pem +8 -0
  18. data/spec/fixtures/certs/ec256-public.pem +4 -0
  19. data/spec/fixtures/certs/ec256-wrong-private.pem +8 -0
  20. data/spec/fixtures/certs/ec256-wrong-public.pem +4 -0
  21. data/spec/fixtures/certs/ec384-private.pem +9 -0
  22. data/spec/fixtures/certs/ec384-public.pem +5 -0
  23. data/spec/fixtures/certs/ec384-wrong-private.pem +9 -0
  24. data/spec/fixtures/certs/ec384-wrong-public.pem +5 -0
  25. data/spec/fixtures/certs/ec512-private.pem +10 -0
  26. data/spec/fixtures/certs/ec512-public.pem +6 -0
  27. data/spec/fixtures/certs/ec512-wrong-private.pem +10 -0
  28. data/spec/fixtures/certs/ec512-wrong-public.pem +6 -0
  29. data/spec/fixtures/certs/rsa-1024-private.pem +15 -0
  30. data/spec/fixtures/certs/rsa-1024-public.pem +6 -0
  31. data/spec/fixtures/certs/rsa-2048-private.pem +27 -0
  32. data/spec/fixtures/certs/rsa-2048-public.pem +9 -0
  33. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +27 -0
  34. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +9 -0
  35. data/spec/fixtures/certs/rsa-4096-private.pem +51 -0
  36. data/spec/fixtures/certs/rsa-4096-public.pem +14 -0
  37. data/spec/jwt/verify_spec.rb +175 -0
  38. data/spec/jwt_spec.rb +1 -181
  39. data/spec/spec_helper.rb +2 -3
  40. metadata +145 -28
  41. data/jwt.gemspec +0 -34
@@ -0,0 +1,98 @@
1
+ require 'jwt/error'
2
+
3
+ module JWT
4
+ # JWT verify methods
5
+ class Verify
6
+ class << self
7
+ %w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub].each do |method_name|
8
+ define_method method_name do |payload, options|
9
+ new(payload, options).send(method_name)
10
+ end
11
+ end
12
+ end
13
+
14
+ def initialize(payload, options)
15
+ @payload = payload
16
+ @options = options
17
+ end
18
+
19
+ def verify_aud
20
+ return unless (options_aud = extract_option(:aud))
21
+
22
+ if @payload['aud'].is_a?(Array)
23
+ fail(
24
+ JWT::InvalidAudError,
25
+ 'Invalid audience'
26
+ ) unless @payload['aud'].include?(options_aud.to_s)
27
+ else
28
+ fail(
29
+ JWT::InvalidAudError,
30
+ "Invalid audience. Expected #{options_aud}, received #{@payload['aud'] || '<none>'}"
31
+ ) unless @payload['aud'].to_s == options_aud.to_s
32
+ end
33
+ end
34
+
35
+ def verify_expiration
36
+ return unless @payload.include?('exp')
37
+
38
+ if @payload['exp'].to_i < (Time.now.to_i - leeway)
39
+ fail(JWT::ExpiredSignature, 'Signature has expired')
40
+ end
41
+ end
42
+
43
+ def verify_iat
44
+ return unless @payload.include?('iat')
45
+
46
+ if !(@payload['iat'].is_a?(Numeric)) || @payload['iat'].to_f > (Time.now.to_f + leeway)
47
+ fail(JWT::InvalidIatError, 'Invalid iat')
48
+ end
49
+ end
50
+
51
+ def verify_iss
52
+ return unless (options_iss = extract_option(:iss))
53
+
54
+ if @payload['iss'].to_s != options_iss.to_s
55
+ fail(
56
+ JWT::InvalidIssuerError,
57
+ "Invalid issuer. Expected #{options_iss}, received #{@payload['iss'] || '<none>'}"
58
+ )
59
+ end
60
+ end
61
+
62
+ def verify_jti
63
+ options_verify_jti = extract_option(:verify_jti)
64
+ if options_verify_jti.respond_to?(:call)
65
+ fail(JWT::InvalidJtiError, 'Invalid jti') unless options_verify_jti.call(@payload['jti'])
66
+ else
67
+ fail(JWT::InvalidJtiError, 'Missing jti') if @payload['jti'].to_s.strip.empty?
68
+ end
69
+ end
70
+
71
+ def verify_not_before
72
+ return unless @payload.include?('nbf')
73
+
74
+ if @payload['nbf'].to_i > (Time.now.to_i + leeway)
75
+ fail(JWT::ImmatureSignature, 'Signature nbf has not been reached')
76
+ end
77
+ end
78
+
79
+ def verify_sub
80
+ return unless (options_sub = extract_option(:sub))
81
+
82
+ fail(
83
+ JWT::InvalidSubError,
84
+ "Invalid subject. Expected #{options_sub}, received #{@payload['sub'] || '<none>'}"
85
+ ) unless @payload['sub'].to_s == options_sub.to_s
86
+ end
87
+
88
+ private
89
+
90
+ def extract_option(key)
91
+ @options.values_at(key.to_sym, key.to_s).compact.first
92
+ end
93
+
94
+ def leeway
95
+ extract_option :leeway
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ # Moments version builder module
4
+ module JWT
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ # Moments version builder module
10
+ module VERSION
11
+ # major version
12
+ MAJOR = 1
13
+ # minor version
14
+ MINOR = 5
15
+ # tiny version
16
+ TINY = 4
17
+ # alpha, beta, etc. tag
18
+ PRE = nil
19
+
20
+ # Build version string
21
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'jwt/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'jwt'
7
+ spec.version = JWT.gem_version
8
+ spec.authors = [
9
+ 'Jeff Lindsay',
10
+ 'Tim Rudat'
11
+ ]
12
+ spec.email = 'timrudat@gmail.com'
13
+ spec.summary = 'JSON Web Token implementation in Ruby'
14
+ spec.description = 'A pure ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT) standard.'
15
+ spec.homepage = 'http://github.com/jwt/ruby-jwt'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = %w(lib)
22
+
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec'
26
+ spec.add_development_dependency 'simplecov'
27
+ spec.add_development_dependency 'simplecov-json'
28
+ spec.add_development_dependency 'codeclimate-test-reporter'
29
+ end
@@ -0,0 +1,8 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BggqhkjOPQMBBw==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MHcCAQEEIJmVse5uPfj6B4TcXrUAvf9/8pJh+KrKKYLNcmOnp/vPoAoGCCqGSM49
6
+ AwEHoUQDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc/DX1wuhIMu8dQzOLSt0tpqK9
7
+ MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==
8
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc
3
+ /DX1wuhIMu8dQzOLSt0tpqK9MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==
4
+ -----END PUBLIC KEY-----
@@ -0,0 +1,8 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQACg==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MHQCAQEEICfA4AaomONdmPTzeyrx5U/jugYXTERyb5U3ETTv7Hx7oAcGBSuBBAAK
6
+ oUQDQgAEPmuXZT3jpJnEMVPOW6RMsmxeGLOCE1PN6fwvUwOsxv7YnyoQ5/bpo64n
7
+ +Jp4slSl1aUNoCBF2oz9bS0iyBo3jg==
8
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPmuXZT3jpJnEMVPOW6RMsmxeGLOCE1PN
3
+ 6fwvUwOsxv7YnyoQ5/bpo64n+Jp4slSl1aUNoCBF2oz9bS0iyBo3jg==
4
+ -----END PUBLIC KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIg==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIGkAgEBBDDxOljqUKw9YNhkluSJIBAYO1YXcNtS+vckd5hpTZ5toxsOlwbmyrnU
6
+ Tn+D5Xma1m2gBwYFK4EEACKhZANiAASQwYTiRvXu1hMHceSosMs/8uf50sJI3jvK
7
+ kdSkvuRAPxSzhtrUvCQDnVsThFq4aOdZZY1qh2ErJGtzmrx+pEsJvJnvfOTG3NGU
8
+ KRalek+LQfVqAUSvDMKlxdkz2e67tso=
9
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkMGE4kb17tYTB3HkqLDLP/Ln+dLCSN47
3
+ ypHUpL7kQD8Us4ba1LwkA51bE4RauGjnWWWNaodhKyRrc5q8fqRLCbyZ73zkxtzR
4
+ lCkWpXpPi0H1agFErwzCpcXZM9nuu7bK
5
+ -----END PUBLIC KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIg==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIGkAgEBBDAfZW47dSKnC5JkSVOk1ERxCIi/IJ1p1WBnVGx4hnrNHy+dxtaZJaF+
6
+ YLInFQ/QbYegBwYFK4EEACKhZANiAAQwXkx4BFBGLXbzl5yVrfxK7er8hSi38iDE
7
+ K2+7cdrR137Wn5JUnL4WTwXTzkyUgfBOL3sHNozwfgU03GD/EOUEKqzsIJiz2cbP
8
+ bFALd4hS+8T4szDLVC9Jl1W6k0CAtmM=
9
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEMF5MeARQRi1285ecla38Su3q/IUot/Ig
3
+ xCtvu3Ha0dd+1p+SVJy+Fk8F085MlIHwTi97BzaM8H4FNNxg/xDlBCqs7CCYs9nG
4
+ z2xQC3eIUvvE+LMwy1QvSZdVupNAgLZj
5
+ -----END PUBLIC KEY-----
@@ -0,0 +1,10 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIw==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIHcAgEBBEIB0/+ffxEj7j62xvGaB5pvzk888e412ESO/EK/K0QlS9dSF8+Rj1rG
6
+ zqpRB8fvDnoe8xdmkW/W5GKzojMyv7YQYumgBwYFK4EEACOhgYkDgYYABAEw74Yw
7
+ aTbPY6TtWmxx6LJDzCX2nKWCPnKdZcEH9Ncu8g5RjRBRq2yacja3OoS6nA2YeDng
8
+ reBJxZr376P6Ns6XcQFWDA6K/MCTrEBCsPxXZNxd8KR9vMGWhgNtWRrcKzwJfQkr
9
+ suyehZkbbYyFnAWyARKHZuV7VUXmeEmRS/f93MPqVA==
10
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBMO+GMGk2z2Ok7VpsceiyQ8wl9pyl
3
+ gj5ynWXBB/TXLvIOUY0QUatsmnI2tzqEupwNmHg54K3gScWa9++j+jbOl3EBVgwO
4
+ ivzAk6xAQrD8V2TcXfCkfbzBloYDbVka3Cs8CX0JK7LsnoWZG22MhZwFsgESh2bl
5
+ e1VF5nhJkUv3/dzD6lQ=
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,10 @@
1
+ -----BEGIN EC PARAMETERS-----
2
+ BgUrgQQAIw==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MIHbAgEBBEG/KbA2oCbiCT6L3V8XSz2WKBy0XhGvIFbl/ZkXIXnkYt+1B7wViSVo
6
+ KCHuMFsi6xU/5nE1EuDG2UsQJmKeAMkIOKAHBgUrgQQAI6GBiQOBhgAEAG0TFWe5
7
+ cZ5DZIyfuysrCoQySTNxd+aT8sPIxsx7mW6YBTsuO6rEgxyegd2Auy4xtikxpzKv
8
+ soMXR02999Aaus2jAAt/wxrhhr41BDP4MV0b6Zngb72hna0pcGqit5OyU8AbOJUZ
9
+ +rdyowRGsOY+aPbOyVhdNcsEdxYC8GdIyCQLBC1H
10
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAbRMVZ7lxnkNkjJ+7KysKhDJJM3F3
3
+ 5pPyw8jGzHuZbpgFOy47qsSDHJ6B3YC7LjG2KTGnMq+ygxdHTb330Bq6zaMAC3/D
4
+ GuGGvjUEM/gxXRvpmeBvvaGdrSlwaqK3k7JTwBs4lRn6t3KjBEaw5j5o9s7JWF01
5
+ ywR3FgLwZ0jIJAsELUc=
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXgIBAAKBgQDO/ahgFDvniFoQ1dm+MdnkBi+Ts5W9AtQNgw4ZHIdPnqEzSgW7
3
+ 0opKEu8hnlLqsIyU2BC2op/xOanipdbXObuFlA6bth1cYRI+YJlR3BbPGOIL6YbJ
4
+ ud9m0gIsBlCDLm4e/E45ZS+emudISP7/SF7zxvxZlnr1z7HTm7nIIVBvuQIDAQAB
5
+ AoGBAMzFQAccvU6GI6O4C5sOsiHUxMh3xtCftaxQVGgfQvVPVuXoeteep1Q0ewFl
6
+ IV4vnkO5pH8pTtVTWG9x5KIy6QCql4qvr2jkOm4mo9uogrpNklvBl2lN4Lxubj0N
7
+ mGRXaM3hckZl8+JT6uzfBfjy+pd8AOigJGPQCOZn4gmANW7pAkEA82Nh4wpj6ZRU
8
+ NBiBq3ONZuH4xJm59MI2FWRJsGUFUYdSaFwyKKim52/13d8iUb7v9utWQFRatCXz
9
+ Lqw9fQyVrwJBANm3dBOVxpUPrYEQsG0q2rdP+u6U3woylxwtQgJxImZKZmmJlPr8
10
+ 9v23rhydvCe1ERPYe7EjF4RGWVPN3KLdExcCQDdzNfL3BApMS97OkoRQQC/nXbjU
11
+ 2SPlN1MqVQuGCG8pqGG0V40h11y1CkvxMS10ldEojq77SOrwFnZUsXGS82sCQQC6
12
+ XdO7QCaxSq5XIRYlHN4EtS40NLOIYy3/LK6osHel4GIyTVd+UjSLk0QzssJxqwln
13
+ V5TqWQO0cxPcLQiFUYEZAkEA2G84ilb9QXOgbNyoE1VifNk49hhodbSskLb86uwY
14
+ Vgtzq1ZsqoPBCasr4WRiXt270n+mo5dNYRlZwiUn9lH78Q==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO/ahgFDvniFoQ1dm+MdnkBi+T
3
+ s5W9AtQNgw4ZHIdPnqEzSgW70opKEu8hnlLqsIyU2BC2op/xOanipdbXObuFlA6b
4
+ th1cYRI+YJlR3BbPGOIL6YbJud9m0gIsBlCDLm4e/E45ZS+emudISP7/SF7zxvxZ
5
+ lnr1z7HTm7nIIVBvuQIDAQAB
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEA4GzZTLU48c4WbyvHi+QKrB71x+T0eq5hqDbQqnlYjhD1Ika7
3
+ io1iplsdJWJuyxfYbUkb2Ol0fj4koZ/GS6lgCZr4+8UHbr1qf0Eu5HZSpszs2YxY
4
+ 8U5RHnrpw67co7hlgAR9HbyNf5XIYgLV9ldHH/eazwnc3F/hgNsV0xjScVilejgo
5
+ cJ4zcsyymvW8t42lteM7bI867ZuJhGop/V+Y0HFyrMsPoQyLuCUpr6ulOfrkr7ZO
6
+ dhAIG8r1HcjOp/AUjM15vfXcbUZjkM/VloifX1YitU3upMGJ8/DpFGffMOImrn5r
7
+ 6BT494V8rRyN2qvQoAkLJpqZ0avLxwiR2lgVQQIDAQABAoIBAEH0Ozgr2fxWEInD
8
+ V/VooypKPvjr9F1JejGxSkmPN9MocKIOH3dsbZ1uEXa3ItBUxan4XlK06SNgp+tH
9
+ xULfF/Y6sQlsse59hBq50Uoa69dRShn1AP6JgZVvkduMPBNxUYL5zrs6emsQXb9Q
10
+ DglDRQfEAJ7vyxSIqQDxYcyT8uSUF70dqFe+E9B2VE3D6ccHc98k41pJrAFAUFH1
11
+ wwvDhfyYr7/Ultut9wzpZvU1meF3Vna3GOUHfxrG6wu1G+WIWHGjouzThsc1qiVI
12
+ BtMCJxuCt5fOXRbU4STbMqhB6sZHiOh6J/dZU6JwRYt+IS8FB6kCNFSEWZWQledJ
13
+ XqtYSQECgYEA9nmnFTRj3fTBq9zMXfCRujkSy6X2bOb39ftNXzHFuc+I6xmv/3Bs
14
+ P9tDdjueP/SnCb7i/9hXkpEIcxjrjiqgcvD2ym1hE4q+odMzRAXYMdnmzI34SVZE
15
+ U5hYJcYsXNKrTTleba7QgqdORmyJ9FwqLO40udvmrZMY223XDwgRkOkCgYEA6RkO
16
+ 5wjjrWWp/G1YN3KXZTS1m2/eGrUThohXKAfAjbWWiouNLW2msXrxEWsPRL6xKiHu
17
+ X9cwZwzi3MstAgk+bphUGUVUkGKNDjWHJA25tDYjbPtkd6xbL4eCHsKpNL3HNYr9
18
+ N0CIvgn7qjaHRBem0iK7T6keY4axaSVddEwYapkCgYEA13K5qaB1F4Smcpt8DTWH
19
+ vPe8xUUaZlFzOJLmLCsuwmB2N8Ppg2j7RspcaxJsH021YaB5ftjWm+ipMSr8ZPY/
20
+ 8JlPsNzxuYpTXtNmAbT2KYVm6THEch61dTk6/DIBf1YrpUJbl5by7vJeStL/uBmE
21
+ SGgksL5XIyzs0opuLdaIvFkCgYAyBLWE8AxjFfCvAQuwAj/ocLITo6KmWnrRIIqL
22
+ RXaVMgUWv7FQsTnW1cnK8g05tC2yG8vZ9wQk6Mf5lwOWb0NdWgSZ0528ydj41pWk
23
+ L+nMeN2LMjqxz2NVxJ8wWJcUgTCxFZ0WcRumo9/D+6V1ABpE9zz4cBLcSnfhVypB
24
+ nV6T6QKBgQCSZNCQ9HPxjAgYcsqc5sjNwuN1GHQZSav3Tye3k6zHENe1lsteT9K8
25
+ xciGIuhybKZBvB4yImIIHCtnH+AS+mHAGqHarjNDMfvjOq0dMibPx4+bkIiHdBIH
26
+ Xz+j5kmntvFiUnzr0Z/Tcqo+r8FvyCo1YWgwqGP8XoFrswD7gy7cZw==
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,9 @@
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-----
@@ -0,0 +1,27 @@
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-----
@@ -0,0 +1,9 @@
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-----
@@ -0,0 +1,51 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIJJwIBAAKCAgEAqETmgWBi5rCmb7euJplA/9xs65+bncc9Yvs5zjyycXSW82Jf
3
+ RuyguGm0OvA2wog24dR4N2kT/87DcGtp5JqJWADVFNr+2V2r6i57/OMLruRpn3p2
4
+ r95dmo0COE+BxPFl7XEBT8JbH57ZtpgcB3/xkS14nLOWFf96hrXPlXJC+VMVKVZm
5
+ A8k2LRh42vT5wUf4U0Doy/p7yFNSFFa6Q8wwe4TBy/z/f+rhFD1w8rxlYjallee/
6
+ ocm7bjZCwbJGMm7orLViqWfsFX3O35PeoJ5h/7uJ7iRwvTFERkTdwWP/0BeKBeIt
7
+ BR3YFc2mut+V9W+WKRkMSL6Crc+oVSx3p8aB7j9SZFzQiRtes4BYETpX1xl2mgIq
8
+ 5hvsFbLw7ESrlIodiwUMTrSIid2DQ6q80kv1zXPr4+Id6L0sJLxPCaXnTmNtasSw
9
+ yedJJYxLjwhHJwtzFAeaq18H3O791YKhjAJ6YxK3zJ59jTE6Pkvqjq183f2PGHVR
10
+ vgSN7aCmI6MBUUB5wDP2K8zX2sh40/uPDVSd6ei1vl3DpPk+h8iExx6AzbohfqZ+
11
+ 5RUUNx127L3MaQvOVC5TxV+R99gwKW++wzcVuO3m2KqVUj+K1uYBy3KBCUMBbckp
12
+ EWGbN++jcdV5oJX6fsC66nOmKlntYwCL/pRww+oLsbzF8J3dxeDbKNF9JDsCAwEA
13
+ AQKCAgBJF8TZJjlP5CQoGy227pNhkSpvH6HFY6qyuFZf09XfmrmHd4/Tiy41bRUx
14
+ FO90iR7t8hFWYHqjf/k9eCtDdi164MGukYJqgVoQG6kYLLgCfI21DMlJk9otLFtu
15
+ gnroRcP05EWhk9dpYONJgcGLMHSKj6n4x7nGTHe41HkbfcrB6ukiT7l4o4q5BAxb
16
+ cFadMtoXr/ZvxJrIZgkddJ7snGHjBcP5DCkgM7MZy6aoilWv1/UNrOF9MdgNA9zz
17
+ rrD3b136x7/XvqC6pS+bxuvJ8YK4R4qeu42NYT07GOcK/pk8lz0JWTodIt2eevqV
18
+ 6lGFj7c2mv7PCpJRVgbVGL/RTVVap/+jbcRVLdnYKsII/dANG7iXnfwRgkLWet5D
19
+ OOsPuvIuyiSaJIwcdRE3SSO+tZhKLt+gh/oLxBPw5Ex0FwsVTtYn3Q/X3EAx+Wph
20
+ eFcRr3TVkDg0MfdWWkgk16DvYB5cWc29coTaH1g+2juadNHbtVAigwJorKc6sxH3
21
+ QGsW0WQJ8ZRZgJkSUuu3nr7QD3ZrgHptONQAh1RWGnIWi6OlMfaPdMo+SDnnL5SG
22
+ mpOPjWadDc1XvMFnKQYMYB5GWU/ZNmnZmDLyg1Pc0Y+qRUc0s83nZFHN60KnUrSz
23
+ 0MZDspSFtr0fMx0b2/EB4EbuXd3QjQURF6P6HtWBu6oFnzu1AQKCAQEA2R9BKJgJ
24
+ vNP+DUu8NBzwmi0cKlAiaxt+w90i5DWq1XWPKgi+RVLkaQSJqHoYQVNgEwL/cWxp
25
+ s2r3GCMNIdOrGdcm8dX/6UYFpRaFcViTycVEA7cwZOMppgqr2Q+ZYX42K7HObUVL
26
+ JGvdEWWWfSsynUGsrG87DC1gl94ANxCdqkZdbW5d3X0w5v7M/1tlrmAeskZSZpeT
27
+ 8BwwM6REb0U/B4/i8TLtLi/PGmMTOIxW41uKS/S6kq/gwyv+jNNO0ljhPt25iSbV
28
+ K5ZHS4YuPKLl0tZMaOkPco9s6t4ES/Y317zQoTzUkAAkkFO4QPzRZL0ESqVBNR0h
29
+ Ao7FLmFZzFHpoQKCAQEAxmZBn0UrJLXkD7bw66y4RwzjQYmxLlkEl3uvjrvVSuL1
30
+ mAHDW58aGIpFFZ8QSTtNewIBQYNifp/cdFHAagqtl/iMGEegaOpJAKu/ykrkfZUp
31
+ 7mYDNng4ZWpypeKaGMAQoNzZiUpF+BDnqbeb/kgYu6sNlh9gRHR79rgAuZQxZ/1B
32
+ tE8WcUFi4CnTq2QLqX4LwMuZHWXAJQoMoW3K5av+J544lIM6GdMJuIONtBBkKVQD
33
+ ErrJ0bqYeykrFS6pKl/NBCZLGo5xFFRiYEdZ1GlA3uW3EGKppz6PS7194+x5UVts
34
+ xZPUfkgdFjWCczkl4JDoWfaNn5sgXtiVbGh1n3gYWwKCAQB7vHEg1kyuXU4qe5/d
35
+ PyTraIvlnVeQHNJIgy0QS3l5Pw8A0IzG6y+anehpqHNMP1zAWPQEytkOVAZPriIc
36
+ xgl7p37dUa0PX0V2SPhxmR5YXeCeEXc197PTmb9H67jos8nhauqOoW/qaMJK2M9D
37
+ tCubLUNf3eAT14R16CHNP93qnUE/TSeXQ3JsIofne0neb47u4F6zcuzvaNEbjSEn
38
+ HJqID7sw5GoA6WQo0I+yqWAXICMXmHf/gtYfxGHEFeSUwexULH5BKG1R8sncw7J0
39
+ Ag3h8xkGrNON4SkcTLy8Iay/eS6YxRcKndo4mk2mU65tr77TX4xi3Z/jWkQLY5WO
40
+ eJwhAoIBABO17wkSxyGDjJ/fDfpsE3bDmgRV2KuBHoqqOBvXH26sM7ghXLZKjT4o
41
+ 5ooqXmTYJm91GIjYs71exnkr8hDW9L4nbEuxOgeSVyRg69H+NMshOaQ8sE8GDJxO
42
+ wgsnAyY4Vq6UomwYW/E0RL/AxRezM/nZGaVzgo3qgLJXP4MwbOQm7hMq1FD2LQuW
43
+ PDhH3Ty+kA5ca97W0Asd/3k+Pi0pNDvdZUOj8e7E369cKoTcKAdPGGsQ8aILhsCd
44
+ q3EUTKwwDl8+KrH9utBJPejQzeTjfBVo/xH6q145QeVFcy9ku/zQN3M9p5vQMEuX
45
+ j1lBMTkpTFw7uYBE2idyHw5BJoZsWQcCggEADfZTChqnOncItSflzGoaAACrr4/x
46
+ KyT/4A+cPMCs11JN9J+EWsCezya2o1l/NF7YPcBR4qjCmFMEiq5GxH5fGLQp0aa7
47
+ V13mHA8XBQ25OW2K7BGJhMHdbuvTnl6jsOfC4+t7P2bUAYxoP6/ncxTzZ5OlBN5k
48
+ aMv9firWl1kSKK75ww9DWn6j0rQ4dBetwX45EMcs+iKIdydg0fmJxR2EJ+uQsCFy
49
+ xcWBEDqV7qLUi6UrAPL3v/DXUv9wKcKOTbKw/aNE8+YTWMUO330GCJ5cVU1eTL5t
50
+ UrcNKOJkFIj7jJUCzv6vcy++hMJEbNXnnTVRnky6e9C2vwzMl33njntapg==
51
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,14 @@
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-----
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+ require 'jwt/verify'
3
+
4
+ module JWT
5
+ RSpec.describe Verify do
6
+ let(:base_payload) { { 'user_id' => 'some@user.tld' } }
7
+ let(:options) { { leeway: 0} }
8
+
9
+ context '.verify_aud(payload, options)' do
10
+ let(:scalar_aud) { 'ruby-jwt-audience' }
11
+ let(:array_aud) { %w(ruby-jwt-aud test-aud ruby-ruby-ruby) }
12
+ let(:scalar_payload) { base_payload.merge('aud' => scalar_aud) }
13
+ let(:array_payload) { base_payload.merge('aud' => array_aud) }
14
+
15
+ it 'must raise JWT::InvalidAudError when the singular audience does not match' do
16
+ expect do
17
+ Verify.verify_aud(scalar_payload, options.merge(aud: 'no-match'))
18
+ end.to raise_error JWT::InvalidAudError
19
+ end
20
+
21
+ it 'must raise JWT::InvalidAudError when the payload has an array and none match the supplied value' do
22
+ expect do
23
+ Verify.verify_aud(array_payload, options.merge(aud: 'no-match'))
24
+ end.to raise_error JWT::InvalidAudError
25
+ end
26
+
27
+ it 'must raise JWT::InvalidAudError when the singular audience does not match and the options aud key is a string' do
28
+ expect do
29
+ Verify.verify_aud(scalar_payload, options.merge('aud' => 'no-match'))
30
+ end.to raise_error JWT::InvalidAudError
31
+ end
32
+
33
+ it 'must allow a matching singular audience to pass' do
34
+ Verify.verify_aud(scalar_payload, options.merge(aud: scalar_aud))
35
+ end
36
+
37
+ it 'must allow a matching audence to pass when the options key is a string' do
38
+ Verify.verify_aud(scalar_payload, options.merge('aud' => scalar_aud))
39
+ end
40
+
41
+ it 'must allow an array with any value matching the one in the options' do
42
+ Verify.verify_aud(array_payload, options.merge(aud: array_aud.first))
43
+ end
44
+
45
+ it 'must allow an array with any value matching the one in the options with a string options key' do
46
+ Verify.verify_aud(array_payload, options.merge('aud' => array_aud.first))
47
+ end
48
+ end
49
+
50
+ context '.verify_expiration(payload, options)' do
51
+ let(:leeway) { 10 }
52
+ let(:payload) { base_payload.merge('exp' => (Time.now.to_i - 5)) }
53
+
54
+ it 'must raise JWT::ExpiredSignature when the token has expired' do
55
+ expect do
56
+ Verify.verify_expiration(payload, options)
57
+ end.to raise_error JWT::ExpiredSignature
58
+ end
59
+
60
+ it 'must allow some leeway in the expiration when configured' do
61
+ Verify.verify_expiration(payload, options.merge(leeway: 10))
62
+ end
63
+ end
64
+
65
+ context '.verify_iat(payload, options)' do
66
+ let(:iat) { Time.now.to_f }
67
+ let(:payload) { base_payload.merge('iat' => iat) }
68
+
69
+ it 'must allow a valid iat' do
70
+ Verify.verify_iat(payload, options)
71
+ end
72
+
73
+ it 'must allow configured leeway' do
74
+ Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(leeway: 70))
75
+ end
76
+
77
+ it 'must properly handle integer times' do
78
+ Verify.verify_iat(payload.merge('iat' => Time.now.to_i), options)
79
+ end
80
+
81
+ it 'must raise JWT::InvalidIatError when the iat value is not Numeric' do
82
+ expect do
83
+ Verify.verify_iat(payload.merge('iat' => 'not a number'), options)
84
+ end.to raise_error JWT::InvalidIatError
85
+ end
86
+
87
+ it 'must raise JWT::InvalidIatError when the iat value is in the future' do
88
+ expect do
89
+ Verify.verify_iat(payload.merge('iat' => (iat + 120)), options)
90
+ end.to raise_error JWT::InvalidIatError
91
+ end
92
+ end
93
+
94
+ context '.verify_iss(payload, options)' do
95
+ let(:iss) { 'ruby-jwt-gem' }
96
+ let(:payload) { base_payload.merge('iss' => iss) }
97
+
98
+ let(:invalid_token) { JWT.encode base_payload, payload[:secret] }
99
+
100
+ it 'must raise JWT::InvalidIssuerError when the configured issuer does not match the payload issuer' do
101
+ expect do
102
+ Verify.verify_iss(payload, options.merge(iss: 'mismatched-issuer'))
103
+ end.to raise_error JWT::InvalidIssuerError
104
+ end
105
+
106
+ it 'must raise JWT::InvalidIssuerError when the payload does not include an issuer' do
107
+ expect do
108
+ Verify.verify_iss(base_payload, options.merge(iss: iss))
109
+ end.to raise_error(JWT::InvalidIssuerError, /received <none>/)
110
+ end
111
+
112
+ it 'must allow a matching issuer to pass' do
113
+ Verify.verify_iss(payload, options.merge(iss: iss))
114
+ end
115
+ end
116
+
117
+ context '.verify_jti(payload, options)' do
118
+ let(:payload) { base_payload.merge('jti' => 'some-random-uuid-or-whatever') }
119
+
120
+ it 'must allow any jti when the verfy_jti key in the options is truthy but not a proc' do
121
+ Verify.verify_jti(payload, options.merge(verify_jti: true))
122
+ end
123
+
124
+ it 'must raise JWT::InvalidJtiError when the jti is missing' do
125
+ expect do
126
+ Verify.verify_jti(base_payload, options)
127
+ end.to raise_error JWT::InvalidJtiError, /missing/i
128
+ end
129
+
130
+ it 'must raise JWT::InvalidJtiError when the jti is an empty string' do
131
+ expect do
132
+ Verify.verify_jti(base_payload.merge('jti' => ' '), options)
133
+ end.to raise_error JWT::InvalidJtiError, /missing/i
134
+ end
135
+
136
+ it 'must raise JWT::InvalidJtiError when verify_jti proc returns false' do
137
+ expect do
138
+ Verify.verify_jti(payload, options.merge(verify_jti: ->(jti) { false }))
139
+ end.to raise_error JWT::InvalidJtiError, /invalid/i
140
+ end
141
+
142
+ it 'true proc should not raise JWT::InvalidJtiError' do
143
+ Verify.verify_jti(payload, options.merge(verify_jti: ->(jti) { true }))
144
+ end
145
+ end
146
+
147
+ context '.verify_not_before(payload, options)' do
148
+ let(:payload) { base_payload.merge('nbf' => (Time.now.to_i + 5)) }
149
+
150
+ it 'must raise JWT::ImmatureSignature when the nbf in the payload is in the future' do
151
+ expect do
152
+ Verify.verify_not_before(payload, options)
153
+ end.to raise_error JWT::ImmatureSignature
154
+ end
155
+
156
+ it 'must allow some leeway in the token age when configured' do
157
+ Verify.verify_not_before(payload, options.merge(leeway: 10))
158
+ end
159
+ end
160
+
161
+ context '.verify_sub(payload, options)' do
162
+ let(:sub) { 'ruby jwt subject' }
163
+
164
+ it 'must raise JWT::InvalidSubError when the subjects do not match' do
165
+ expect do
166
+ Verify.verify_sub(base_payload.merge('sub' => 'not-a-match'), options.merge(sub: sub))
167
+ end.to raise_error JWT::InvalidSubError
168
+ end
169
+
170
+ it 'must allow a matching sub' do
171
+ Verify.verify_sub(base_payload.merge('sub' => sub), options.merge(sub: sub))
172
+ end
173
+ end
174
+ end
175
+ end