jwt-rack 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bef98cd84654986f72aac0d1b8fc9a64f762bd0e784e39929e15893a3868c586
4
- data.tar.gz: 8b70bf2c4dcd2ea7b92fed3c6121c834195eb9365a320acacbd7ff639ad20f2e
3
+ metadata.gz: 75d32bd64c673a5aac017606f4599fb69dbbff77ff1bd1e2ce24539d1394c4d5
4
+ data.tar.gz: 602cf6f50f172758e1be322196091e27ccfa1dadb7b50574b2e985e60013edee
5
5
  SHA512:
6
- metadata.gz: fe5702dd93cecb195a467a1f037c67a7d052ebabb67714d131ed118e34755b6c2155bec6b13853c4df8d0ad9c49a7c578efa2d2bc4de106b1919ee5e9a286eda
7
- data.tar.gz: 28ec9ecb2e24e958cee55899054589ff55a35dc7bb86f9e80cb322e958747157de2f37e60b249878c792e454100d4b7c6608c066b1c319a5c51cc03f200d7328
6
+ metadata.gz: f5b44a1728ec958adee9246e5e59c37e975683d4bb46c6147c610bd5d0083906c38dc7811182d574ce87b78e747c574c0a4a1582ed1a7e6fd66723168d77bce7
7
+ data.tar.gz: 65eca4b7d2f3ea28d6e2ad842ed1b71b48c7c8db5834ba675b9c29213da6b258488056e1b403976587f1466160c37411d9c68a41d2e7db9555f3f317d5938743
data/.gitignore CHANGED
@@ -7,5 +7,7 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
 
10
+ Gemfile.lock
11
+
10
12
  # rspec failure tracking
11
13
  .rspec_status
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in jwt-rack.gemspec
4
6
  gemspec
data/README.md CHANGED
@@ -8,6 +8,8 @@
8
8
 
9
9
  This gem provides JSON Web Token (JWT) based authentication.
10
10
 
11
+ #### TODO: Mention original gem [source](https://github.com/eparreno/rack-jwt)
12
+
11
13
  ## Requirements
12
14
 
13
15
  - Ruby 2.3.8 or greater
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "jwt/rack"
4
+ require 'bundler/setup'
5
+ require 'jwt/rack'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "jwt/rack"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start(__FILE__)
@@ -1,41 +1,44 @@
1
- lib = File.expand_path("lib", __dir__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "jwt/rack/version"
5
+ require 'jwt/rack/version'
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = "jwt-rack"
7
- spec.version = Jwt::Rack::VERSION
8
- spec.authors = ["Yaroslav Savchuk"]
9
- spec.email = ["savchukyarpolk@gmail.com"]
8
+ spec.name = 'jwt-rack'
9
+ spec.version = JWT::Rack::VERSION
10
+ spec.authors = ['Yaroslav Savchuk']
11
+ spec.email = ['savchukyarpolk@gmail.com']
10
12
 
11
- spec.summary = %q{Rack middleware that provides authentication based on JSON Web Tokens.}
12
- spec.description = %q{Rack middleware that provides authentication based on JSON Web Tokens.}
13
- spec.homepage = "https://github.com/ysv/jwt-rack"
14
- spec.license = "MIT"
13
+ spec.summary = 'Rack middleware that provides authentication based on JSON Web Tokens.'
14
+ spec.description = 'Rack middleware that provides authentication based on JSON Web Tokens.'
15
+ spec.homepage = 'https://github.com/ysv/jwt-rack'
16
+ spec.license = 'MIT'
15
17
 
16
- spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = "https://github.com/ysv/jwt-rack"
18
- spec.metadata["changelog_uri"] = "https://github.com/ysv/jwt-rack/blob/master/CHANGELOG.md"
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/ysv/jwt-rack'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/ysv/jwt-rack/blob/master/CHANGELOG.md'
19
21
 
20
22
  # Specify which files should be added to the gem when it is released.
21
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
25
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
26
  end
25
- spec.bindir = "exe"
27
+ spec.bindir = 'exe'
26
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
- spec.require_paths = ["lib"]
29
+ spec.require_paths = ['lib']
28
30
 
29
31
  spec.platform = Gem::Platform::RUBY
30
32
  spec.required_ruby_version = '>= 2.3.8'
31
33
 
32
- spec.add_development_dependency 'bundler', '>= 1.16.2'
33
- spec.add_development_dependency 'rake', '>= 12.0.0'
34
+ spec.add_development_dependency 'bundler', '>= 1.16.2'
35
+ spec.add_development_dependency 'pry-byebug', '~> 3.7'
34
36
  spec.add_development_dependency 'rack-test', '>= 1.0.0'
37
+ spec.add_development_dependency 'rake', '>= 12.0.0'
38
+ spec.add_development_dependency 'rbnacl', '>= 6.0.1'
35
39
  spec.add_development_dependency 'rspec', '>= 3.8.0'
36
40
  spec.add_development_dependency 'simplecov', '>= 0.16.0'
37
- spec.add_development_dependency 'rbnacl', '>= 6.0.1'
38
41
 
42
+ spec.add_runtime_dependency 'jwt', '~> 2.1.0'
39
43
  spec.add_runtime_dependency 'rack'
40
- spec.add_runtime_dependency 'jwt', '~> 2.1.0'
41
44
  end
@@ -1,8 +1,10 @@
1
- require "jwt/rack/version"
1
+ # frozen_string_literal: true
2
2
 
3
- module Jwt
3
+ require 'jwt/rack/version'
4
+
5
+ module JWT
4
6
  module Rack
5
- class Error < StandardError; end
6
- # Your code goes here...
7
+ autoload :Auth, 'jwt/rack/auth'
8
+ autoload :Token, 'jwt/rack/token'
7
9
  end
8
10
  end
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jwt'
4
+
5
+ module JWT
6
+ module Rack
7
+ # Authentication middleware
8
+ class Auth
9
+ attr_reader :secret
10
+ attr_reader :verify
11
+ attr_reader :options
12
+ attr_reader :exclude
13
+
14
+ SUPPORTED_ALGORITHMS = [
15
+ 'none',
16
+ 'HS256',
17
+ 'HS384',
18
+ 'HS512',
19
+ 'RS256',
20
+ 'RS384',
21
+ 'RS512',
22
+ 'ES256',
23
+ 'ES384',
24
+ 'ES512',
25
+ ('ED25519' if defined?(RbNaCl))
26
+ ].compact.freeze
27
+
28
+ DEFAULT_ALGORITHM = 'HS256'
29
+
30
+ # The last segment gets dropped for 'none' algorithm since there is no
31
+ # signature so both of these patterns are valid. All character chunks
32
+ # are base64url format and periods.
33
+ # Bearer abc123.abc123.abc123
34
+ # Bearer abc123.abc123.
35
+ BEARER_TOKEN_REGEX = %r{
36
+ ^Bearer\s{1}( # starts with Bearer and a single space
37
+ [a-zA-Z0-9\-\_]+\. # 1 or more chars followed by a single period
38
+ [a-zA-Z0-9\-\_]+\. # 1 or more chars followed by a single period
39
+ [a-zA-Z0-9\-\_]* # 0 or more chars, no trailing chars
40
+ )$
41
+ }x.freeze
42
+
43
+ JWT_DECODE_ERRORS = [
44
+ ::JWT::DecodeError,
45
+ ::JWT::VerificationError,
46
+ ::JWT::ExpiredSignature,
47
+ ::JWT::IncorrectAlgorithm,
48
+ ::JWT::ImmatureSignature,
49
+ ::JWT::InvalidIssuerError,
50
+ ::JWT::InvalidIatError,
51
+ ::JWT::InvalidAudError,
52
+ ::JWT::InvalidSubError,
53
+ ::JWT::InvalidJtiError,
54
+ ::JWT::InvalidPayload
55
+ ].freeze
56
+
57
+ MissingAuthHeader = Class.new(StandardError)
58
+ InvalidAuthHeaderFormat = Class.new(StandardError)
59
+
60
+ ERRORS_TO_RESCUE = (JWT_DECODE_ERRORS + [MissingAuthHeader, InvalidAuthHeaderFormat]).freeze
61
+
62
+ # Initialization should fail fast with an ArgumentError
63
+ # if any args are invalid.
64
+ def initialize(app, opts = {})
65
+ @app = app
66
+ @secret = opts.fetch(:secret, nil)
67
+ @verify = opts.fetch(:verify, true)
68
+ @options = opts.fetch(:options, {})
69
+ @exclude = opts.fetch(:exclude, [])
70
+
71
+ @on_error = opts.fetch(:on_error, method(:default_on_error))
72
+
73
+ @secret = @secret.strip if @secret.is_a?(String)
74
+ @options[:algorithm] = DEFAULT_ALGORITHM if @options[:algorithm].nil?
75
+
76
+ check_secret_type!
77
+ check_secret!
78
+ check_secret_and_verify_for_none_alg!
79
+ check_verify_type!
80
+ check_options_type!
81
+ check_valid_algorithm!
82
+ check_exclude_type!
83
+ check_on_error_callable!
84
+ end
85
+
86
+ def call(env)
87
+ if path_matches_excluded_path?(env)
88
+ @app.call(env)
89
+ else
90
+ verify_token(env)
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def verify_token(env)
97
+ raise MissingAuthHeader if missing_auth_header?(env)
98
+ raise InvalidAuthHeaderFormat if invalid_auth_header?(env)
99
+
100
+ # extract the token from the Authorization: Bearer header
101
+ # with a regex capture group.
102
+ token = BEARER_TOKEN_REGEX.match(env['HTTP_AUTHORIZATION'])[1]
103
+
104
+ decoded_token = Token.decode(token, @secret, @verify, @options)
105
+ env['jwt.payload'] = decoded_token.first
106
+ env['jwt.header'] = decoded_token.last
107
+ @app.call(env)
108
+ rescue *ERRORS_TO_RESCUE => e
109
+ @on_error.call(e)
110
+ end
111
+
112
+ def check_secret_type!
113
+ unless Token.secret_of_valid_type?(@secret)
114
+ raise ArgumentError, 'secret argument must be a valid type'
115
+ end
116
+ end
117
+
118
+ def check_secret!
119
+ if @secret.nil? || (@secret.is_a?(String) && @secret.empty?)
120
+ unless @options[:algorithm] == 'none'
121
+ raise ArgumentError, 'secret argument can only be nil/empty for the "none" algorithm'
122
+ end
123
+ end
124
+ end
125
+
126
+ def check_secret_and_verify_for_none_alg!
127
+ if @options && @options[:algorithm] && @options[:algorithm] == 'none'
128
+ unless @secret.nil? && @verify.is_a?(FalseClass)
129
+ raise ArgumentError, 'when "none" the secret must be "nil" and verify "false"'
130
+ end
131
+ end
132
+ end
133
+
134
+ def check_verify_type!
135
+ unless verify.is_a?(TrueClass) || verify.is_a?(FalseClass)
136
+ raise ArgumentError, 'verify argument must be true or false'
137
+ end
138
+ end
139
+
140
+ def check_options_type!
141
+ raise ArgumentError, 'options argument must be a Hash' unless options.is_a?(Hash)
142
+ end
143
+
144
+ def check_valid_algorithm!
145
+ unless @options &&
146
+ @options[:algorithm] &&
147
+ SUPPORTED_ALGORITHMS.include?(@options[:algorithm])
148
+ raise ArgumentError, 'algorithm argument must be a supported type'
149
+ end
150
+ end
151
+
152
+ def check_exclude_type!
153
+ raise ArgumentError, 'exclude argument must be an Array' unless @exclude.is_a?(Array)
154
+
155
+ @exclude.each do |x|
156
+ raise ArgumentError, 'each exclude Array element must be a String' unless x.is_a?(String)
157
+
158
+ raise ArgumentError, 'each exclude Array element must not be empty' if x.empty?
159
+
160
+ unless x.start_with?('/')
161
+ raise ArgumentError, 'each exclude Array element must start with a /'
162
+ end
163
+ end
164
+ end
165
+
166
+ def check_on_error_callable!
167
+ unless @on_error.respond_to?(:call)
168
+ raise ArgumentError, 'on_error argument must respond to call'
169
+ end
170
+ end
171
+
172
+ def path_matches_excluded_path?(env)
173
+ @exclude.any? { |ex| env['PATH_INFO'].start_with?(ex) }
174
+ end
175
+
176
+ def valid_auth_header?(env)
177
+ env['HTTP_AUTHORIZATION'] =~ BEARER_TOKEN_REGEX
178
+ end
179
+
180
+ def invalid_auth_header?(env)
181
+ !valid_auth_header?(env)
182
+ end
183
+
184
+ def missing_auth_header?(env)
185
+ env['HTTP_AUTHORIZATION'].nil? || env['HTTP_AUTHORIZATION'].strip.empty?
186
+ end
187
+
188
+ def default_on_error(error)
189
+ error_message = {
190
+ ::JWT::DecodeError => 'Invalid JWT token : Decode Error',
191
+ ::JWT::VerificationError => 'Invalid JWT token : Signature Verification Error',
192
+ ::JWT::ExpiredSignature => 'Invalid JWT token : Expired Signature (exp)',
193
+ ::JWT::IncorrectAlgorithm => 'Invalid JWT token : Incorrect Key Algorithm',
194
+ ::JWT::ImmatureSignature => 'Invalid JWT token : Immature Signature (nbf)',
195
+ ::JWT::InvalidIssuerError => 'Invalid JWT token : Invalid Issuer (iss)',
196
+ ::JWT::InvalidIatError => 'Invalid JWT token : Invalid Issued At (iat)',
197
+ ::JWT::InvalidAudError => 'Invalid JWT token : Invalid Audience (aud)',
198
+ ::JWT::InvalidSubError => 'Invalid JWT token : Invalid Subject (sub)',
199
+ ::JWT::InvalidJtiError => 'Invalid JWT token : Invalid JWT ID (jti)',
200
+ ::JWT::InvalidPayload => 'Invalid JWT token : Invalid Payload',
201
+ MissingAuthHeader => 'Missing Authorization header',
202
+ InvalidAuthHeaderFormat => 'Invalid Authorization header format'
203
+ }
204
+ message = error_message.fetch(error.class)
205
+ body = { error: message }.to_json
206
+ headers = { 'Content-Type' => 'application/json', 'Content-Length' => body.bytesize.to_s }
207
+
208
+ [401, headers, [body]]
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ module Rack
5
+ # Token encoding and decoding
6
+ class Token
7
+ # abc123.abc123.abc123 (w/ signature)
8
+ # abc123.abc123. ('none')
9
+ TOKEN_REGEX = /\A([a-zA-Z0-9\-\_\~\+\\]+\.[a-zA-Z0-9\-\_\~\+\\]+\.[a-zA-Z0-9\-\_\~\+\\]*)\z/.freeze
10
+ DEFAULT_HEADERS = { typ: 'JWT' }.freeze
11
+
12
+ def self.encode(payload, secret, alg = 'HS256')
13
+ raise 'Invalid payload. Must be a Hash.' unless payload.is_a?(Hash)
14
+ raise 'Invalid secret type.' unless secret_of_valid_type?(secret)
15
+ raise 'Unsupported algorithm' unless algorithm_supported?(alg)
16
+
17
+ # if using an unsigned token ('none' alg) you *must* set the `secret`
18
+ # to `nil` in which case any user provided `secret` will be ignored.
19
+ if alg == 'none'
20
+ ::JWT.encode(payload, nil, alg, DEFAULT_HEADERS)
21
+ else
22
+ ::JWT.encode(payload, secret, alg, DEFAULT_HEADERS)
23
+ end
24
+ end
25
+
26
+ def self.decode(token, secret, verify, options = {})
27
+ raise 'Invalid token format.' unless valid_token_format?(token)
28
+ raise 'Invalid secret type.' unless secret_of_valid_type?(secret)
29
+ raise 'Unsupported verify value.' unless verify_of_valid_type?(verify)
30
+
31
+ options[:algorithm] = 'HS256' if options[:algorithm].nil?
32
+ raise 'Unsupported algorithm' unless algorithm_supported?(options[:algorithm])
33
+
34
+ # If using an unsigned 'none' algorithm token you *must* set the
35
+ # `secret` to `nil` and `verify` to `false` or it won't work per
36
+ # the ruby-jwt docs. Using 'none' is probably not recommended.
37
+ if options[:algorithm] == 'none'
38
+ ::JWT.decode(token, nil, false, options)
39
+ else
40
+ ::JWT.decode(token, secret, verify, options)
41
+ end
42
+ end
43
+
44
+ def self.secret_of_valid_type?(secret)
45
+ secret.nil? ||
46
+ secret.is_a?(String) ||
47
+ secret.is_a?(OpenSSL::PKey::RSA) ||
48
+ secret.is_a?(OpenSSL::PKey::EC) ||
49
+ (defined?(RbNaCl) && secret.is_a?(RbNaCl::Signatures::Ed25519::SigningKey)) ||
50
+ (defined?(RbNaCl) && secret.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey))
51
+ end
52
+
53
+ # Private Utility Class Methods
54
+ # See : https://gist.github.com/Integralist/bb8760d11a03c88da151
55
+
56
+ def self.valid_token_format?(token)
57
+ token =~ TOKEN_REGEX
58
+ end
59
+ private_class_method :valid_token_format?
60
+
61
+ def self.algorithm_supported?(alg)
62
+ JWT::Rack::Auth::SUPPORTED_ALGORITHMS.include?(alg)
63
+ end
64
+ private_class_method :algorithm_supported?
65
+
66
+ def self.verify_of_valid_type?(verify)
67
+ verify.nil? || verify.is_a?(FalseClass) || verify.is_a?(TrueClass)
68
+ end
69
+ private_class_method :verify_of_valid_type?
70
+ end
71
+ end
72
+ end
@@ -1,5 +1,7 @@
1
- module Jwt
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
2
4
  module Rack
3
- VERSION = "0.0.0"
5
+ VERSION = '0.1.0'
4
6
  end
5
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt-rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yaroslav Savchuk
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.16.2
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: pry-byebug
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 12.0.0
33
+ version: '3.7'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 12.0.0
40
+ version: '3.7'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rack-test
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,61 +53,61 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.0.0
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 3.8.0
61
+ version: 12.0.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 3.8.0
68
+ version: 12.0.0
69
69
  - !ruby/object:Gem::Dependency
70
- name: simplecov
70
+ name: rbnacl
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: 0.16.0
75
+ version: 6.0.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 0.16.0
82
+ version: 6.0.1
83
83
  - !ruby/object:Gem::Dependency
84
- name: rbnacl
84
+ name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: 6.0.1
89
+ version: 3.8.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: 6.0.1
96
+ version: 3.8.0
97
97
  - !ruby/object:Gem::Dependency
98
- name: rack
98
+ name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
103
+ version: 0.16.0
104
+ type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: 0.16.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: jwt
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 2.1.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: rack
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  description: Rack middleware that provides authentication based on JSON Web Tokens.
126
140
  email:
127
141
  - savchukyarpolk@gmail.com
@@ -141,6 +155,8 @@ files:
141
155
  - bin/setup
142
156
  - jwt-rack.gemspec
143
157
  - lib/jwt/rack.rb
158
+ - lib/jwt/rack/auth.rb
159
+ - lib/jwt/rack/token.rb
144
160
  - lib/jwt/rack/version.rb
145
161
  homepage: https://github.com/ysv/jwt-rack
146
162
  licenses:
@@ -164,7 +180,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
180
  - !ruby/object:Gem::Version
165
181
  version: '0'
166
182
  requirements: []
167
- rubygems_version: 3.0.3
183
+ rubyforge_project:
184
+ rubygems_version: 2.7.8
168
185
  signing_key:
169
186
  specification_version: 4
170
187
  summary: Rack middleware that provides authentication based on JSON Web Tokens.