rack-jwt 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2cdc1b0bd5715e4d4d5e8cd04822d0e6825b089f
4
- data.tar.gz: 2397aac243a1d587e109f46942cecdaaccb9b5cd
3
+ metadata.gz: 19267b5f494a49fb28e4a58a34a51aed16313480
4
+ data.tar.gz: 085968e3d783b4e7e1bcc13cf85e0944da44a97e
5
5
  SHA512:
6
- metadata.gz: 1ccae31dc0d69b94d0da8243276c532b2793dbae1563da3b328a163d9f03f5284abb58f60a193b8e421591ca9f9ff0e2b1b6bac9dcd80a0954525b6ffd25d371
7
- data.tar.gz: 03b28fa23d5d00bce804435ff76c6e1dd4f873f6c5d49bf8830ee5295ad747d90e5dbfba7fcb371d34f58968534fb7725e1545272ec82a48f78b582808f62019
6
+ metadata.gz: 95d36e6594b6cae68ec827bc7b53774814ce42a8a1d551ef99d697c7ed28fce6dfb30ff8a62c0f3644f6070d51b6d22ee6dbb09897366323a4059b7dce696a97
7
+ data.tar.gz: 9a7b0274512ba049c1a76071c7fb9850e4f36ba5b55d4401054a3206ef095b99c22340d0f12530796e8dea0f6c8f57dfa67539f9a81f10426336e9558c7c5128
data/README.md CHANGED
@@ -24,16 +24,30 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
- ### sinatra
27
+ `Rack::JWT::Auth` accepts several configuration options:
28
+
29
+ * `secret` : required : String : A cryptographically secure String that serves as the HMAC SHA-256 secret for the JSON Web Token.
30
+ * `verify` : optional : Boolean : Determines whether JWT will verify tokens when decoded. Default is `true`.
31
+ * `options` : optional : Hash : A hash of options that are passed through to JWT to configure supported claims. See [the ruby-jwt docs](https://github.com/progrium/ruby-jwt#support-for-reserved-claim-names) for the available options. By default only expiration (exp) and Not Before (nbf) claims are verified.
32
+ * `exclude` : optional : Array : An Array of path strings representing paths that should not check for JWT authentication tokens before allowing access.
33
+
34
+
35
+ ### Sinatra
36
+
37
+ ```
38
+ use Rack::JWT::Auth, secret: 'you_secret_token_goes_here', verify: true, options: {}, exclude: ['/api/docs']
39
+ ```
40
+
41
+ ### Cuba
28
42
 
29
43
  ```
30
- use Rack::JWT::Auth secret: 'you_secret_token_goes_here', exclude: ['/api/docs']
44
+ Cuba.use Rack::JWT::Auth, secret: 'you_secret_token_goes_here', verify: true, options: {}, exclude: ['/api/docs']
31
45
  ```
32
46
 
33
47
  ### Rails
34
48
 
35
49
  ```
36
- Rails.application.config.middleware.use, Rack::JWT::Auth, secret: Rails.application.secrets.secret_key_base, exclude: ['/api/docs']
50
+ Rails.application.config.middleware.use, Rack::JWT::Auth, secret: Rails.application.secrets.secret_key_base, verify: true, options: {}, exclude: ['/api/docs']
37
51
  ```
38
52
 
39
53
  ## Generating tokens
data/lib/rack/jwt/auth.rb CHANGED
@@ -5,7 +5,9 @@ module Rack
5
5
  class Auth
6
6
  def initialize(app, opts = {})
7
7
  @app = app
8
- @secret = opts.fetch(:secret)
8
+ @jwt_secret = opts.fetch(:secret)
9
+ @jwt_verify = opts.fetch(:verify, true)
10
+ @jwt_options = opts.fetch(:options, {})
9
11
  @exclude = opts.fetch(:exclude, [])
10
12
  end
11
13
 
@@ -23,11 +25,11 @@ module Rack
23
25
  if valid_header?(env)
24
26
  begin
25
27
  token = env['HTTP_AUTHORIZATION'].split(' ')[-1]
26
- decoded_token = Token.decode(token, @secret)
27
- env['jwt.header'] = decoded_token.last
28
- env['jwt.payload'] = decoded_token.first
28
+ decoded_token = Token.decode(token, @jwt_secret, @jwt_verify, @jwt_options)
29
+ env['jwt.header'] = decoded_token.last unless decoded_token.nil?
30
+ env['jwt.payload'] = decoded_token.first unless decoded_token.nil?
29
31
  @app.call(env)
30
- rescue
32
+ rescue ::JWT::DecodeError
31
33
  return_error('Invalid JWT token')
32
34
  end
33
35
  else
@@ -1,15 +1,14 @@
1
1
  module Rack
2
2
  module JWT
3
3
  class Token
4
+ # TODO : Support all algorithms, not just default 'HS256'
5
+ # https://github.com/progrium/ruby-jwt#algorithms-and-usage
4
6
  def self.encode(payload, secret)
5
- ::JWT.encode(payload, secret)
7
+ ::JWT.encode(payload, secret, 'HS256')
6
8
  end
7
9
 
8
- def self.decode(token, secret)
9
- ::JWT.decode(token, secret)
10
- rescue
11
- # It will raise an error if it is not a valid token due to any reason
12
- nil
10
+ def self.decode(token, secret, verify, options)
11
+ ::JWT.decode(token, secret, verify, options)
13
12
  end
14
13
  end
15
14
  end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
- module Jwt
3
- VERSION = "0.1.1"
2
+ module JWT
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
data/rack-jwt.gemspec CHANGED
@@ -5,7 +5,7 @@ require 'rack/jwt/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "rack-jwt"
8
- spec.version = Rack::Jwt::VERSION
8
+ spec.version = Rack::JWT::VERSION
9
9
  spec.authors = ["Mr. Eigenbart"]
10
10
  spec.email = ["eigenbart@gmail.com"]
11
11
  spec.summary = %q{Rack middleware that provides authentication based on JSON Web Tokens.}
@@ -25,5 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'rspec', '~> 3.2.0'
26
26
 
27
27
  spec.add_runtime_dependency 'rack', '>= 1.6.0'
28
- spec.add_runtime_dependency 'jwt', '~> 1.2.1'
28
+ spec.add_runtime_dependency 'jwt', '~> 1.5.0'
29
29
  end
data/spec/auth_spec.rb CHANGED
@@ -3,16 +3,18 @@ require 'spec_helper'
3
3
  describe Rack::JWT::Auth do
4
4
  include Rack::Test::Methods
5
5
 
6
- let(:issuer) { Rack::JWT::Token }
7
- let(:secret) { 'foo' }
8
- let(:body) {{ 'foo' => 'bar' }}
6
+ let(:issuer) { Rack::JWT::Token }
7
+ let(:secret) { 'foo' }
8
+ let(:verify) { true }
9
+ let(:options) { {} }
10
+ let(:body) {{ 'foo' => 'bar' }}
9
11
 
10
12
  let(:app) do
11
13
  main_app = lambda { |env| [200, env, [body.to_json]] }
12
14
  Rack::JWT::Auth.new(main_app, { secret: secret })
13
15
  end
14
16
 
15
- before do
17
+ def perform_request
16
18
  get('/', {}, headers)
17
19
  end
18
20
 
@@ -29,6 +31,8 @@ describe Rack::JWT::Auth do
29
31
 
30
32
  subject { JSON.parse(last_response.body) }
31
33
 
34
+ before { perform_request }
35
+
32
36
  it 'returns 401 status code' do
33
37
  expect(last_response.status).to eq(401)
34
38
  end
@@ -38,12 +42,14 @@ describe Rack::JWT::Auth do
38
42
  end
39
43
  end
40
44
 
41
- context 'when authorzation header does not contain the schema' do
45
+ context 'when authorization header does not contain the schema' do
42
46
  let(:token) { issuer.encode({ iss: 1 }, secret) }
43
47
  let(:headers) {{ 'HTTP_AUTHORIZATION' => token }}
44
48
 
45
49
  subject { JSON.parse(last_response.body) }
46
50
 
51
+ before { perform_request }
52
+
47
53
  it 'returns 401 status code' do
48
54
  expect(last_response.status).to eq(401)
49
55
  end
@@ -59,6 +65,8 @@ describe Rack::JWT::Auth do
59
65
 
60
66
  subject { JSON.parse(last_response.body) }
61
67
 
68
+ before { perform_request }
69
+
62
70
  it 'returns 401 status code' do
63
71
  expect(last_response.status).to eq(401)
64
72
  end
@@ -74,6 +82,8 @@ describe Rack::JWT::Auth do
74
82
 
75
83
  subject { JSON.parse(last_response.body) }
76
84
 
85
+ before { perform_request }
86
+
77
87
  it 'returns 401 status code' do
78
88
  expect(last_response.status).to eq(401)
79
89
  end
@@ -83,12 +93,31 @@ describe Rack::JWT::Auth do
83
93
  end
84
94
  end
85
95
 
96
+ context 'when token signature is invalid and JWT verify option is false' do
97
+ let(:app) do
98
+ main_app = lambda { |env| [200, env, [body.to_json]] }
99
+ Rack::JWT::Auth.new(main_app, { secret: secret, verify: false })
100
+ end
101
+ let(:token) { issuer.encode({ iss: 1 }, 'invalid secret') }
102
+ let(:headers) {{ 'HTTP_AUTHORIZATION' => "Bearer #{token}" }}
103
+
104
+ before { perform_request }
105
+
106
+ subject { JSON.parse(last_response.body) }
107
+
108
+ it 'returns 200 status code' do
109
+ expect(last_response.status).to eq(200)
110
+ end
111
+ end
112
+
86
113
  context 'when token is valid' do
87
114
  let(:token) { issuer.encode({ iss: 1 }, secret) }
88
115
  let(:headers) {{ 'HTTP_AUTHORIZATION' => "Bearer #{token}" }}
89
116
 
90
117
  subject { JSON.parse(last_response.body) }
91
118
 
119
+ before { perform_request }
120
+
92
121
  it 'returns 200 status code' do
93
122
  expect(last_response.status).to eq(200)
94
123
  end
@@ -108,4 +137,107 @@ describe Rack::JWT::Auth do
108
137
  expect(header['typ']).to eq('JWT')
109
138
  end
110
139
  end
140
+
141
+ context 'when token is valid but app raises an error unrelated to JWT' do
142
+ let(:token) { issuer.encode({ iss: 1 }, secret) }
143
+ let(:headers) {{ 'HTTP_AUTHORIZATION' => "Bearer #{token}" }}
144
+
145
+ let(:app) do
146
+ main_app = lambda { |env| raise 'BOOM!' }
147
+ Rack::JWT::Auth.new(main_app, { secret: secret })
148
+ end
149
+
150
+ it 'bubbles up the exception' do
151
+ expect { perform_request }.to raise_error('BOOM!')
152
+ end
153
+ end
154
+
155
+ # Test the pass-through of the options Hash to JWT using Issued At (iat) claim to test..
156
+ ###
157
+
158
+ context 'when token is valid and an invalid Issued At (iat) claim is provided JWT should ignore bad iat by default' do
159
+ let(:token) { issuer.encode({ iss: 1, iat: Time.now.to_i + 1000000 }, secret) }
160
+ let(:headers) {{ 'HTTP_AUTHORIZATION' => "Bearer #{token}" }}
161
+
162
+ before { perform_request }
163
+
164
+ subject { JSON.parse(last_response.body) }
165
+
166
+ it 'returns 200 status code' do
167
+ expect(last_response.status).to eq(200)
168
+ end
169
+
170
+ it 'process the request' do
171
+ expect(subject).to eq(body)
172
+ end
173
+
174
+ it 'adds the token payload to the request' do
175
+ payload = last_response.header['jwt.payload']
176
+ expect(payload['iss']).to eq(1)
177
+ end
178
+
179
+ it 'adds the token header to the request' do
180
+ header = last_response.header['jwt.header']
181
+ expect(header['alg']).to eq('HS256')
182
+ expect(header['typ']).to eq('JWT')
183
+ end
184
+ end
185
+
186
+ context 'when token is valid and an invalid Issued At (iat) claim is provided and iat verification option is enabled' do
187
+ # The token was issued at an insane time in the future.
188
+ let(:iat) { Time.now.to_i + 1000000 }
189
+ let(:app) do
190
+ main_app = lambda { |env| [200, env, [body.to_json]] }
191
+ Rack::JWT::Auth.new(main_app, { secret: secret, options: { :verify_iat => true } })
192
+ end
193
+ let(:token) { issuer.encode({ iss: 1, iat: iat }, secret) }
194
+ let(:headers) {{ 'HTTP_AUTHORIZATION' => "Bearer #{token}" }}
195
+
196
+ before { perform_request }
197
+
198
+ subject { JSON.parse(last_response.body) }
199
+
200
+ it 'returns 401 status code' do
201
+ expect(last_response.status).to eq(401)
202
+ end
203
+
204
+ it 'returns an error message' do
205
+ expect(subject['error']).to eq('Invalid JWT token')
206
+ end
207
+ end
208
+
209
+ context 'when token is valid and a valid Issued At (iat) claim is provided and iat verification option is enabled' do
210
+ # The token was issued at a sane Time.now
211
+ let(:iat) { Time.now.to_i }
212
+ let(:app) do
213
+ main_app = lambda { |env| [200, env, [body.to_json]] }
214
+ Rack::JWT::Auth.new(main_app, { secret: secret, options: { :verify_iat => true } })
215
+ end
216
+ let(:token) { issuer.encode({ iss: 1, iat: iat }, secret) }
217
+ let(:headers) {{ 'HTTP_AUTHORIZATION' => "Bearer #{token}" }}
218
+
219
+ before { perform_request }
220
+
221
+ subject { JSON.parse(last_response.body) }
222
+
223
+ it 'returns 200 status code' do
224
+ expect(last_response.status).to eq(200)
225
+ end
226
+
227
+ it 'process the request' do
228
+ expect(subject).to eq(body)
229
+ end
230
+
231
+ it 'adds the token payload to the request' do
232
+ payload = last_response.header['jwt.payload']
233
+ expect(payload['iss']).to eq(1)
234
+ end
235
+
236
+ it 'adds the token header to the request' do
237
+ header = last_response.header['jwt.header']
238
+ expect(header['alg']).to eq('HS256')
239
+ expect(header['typ']).to eq('JWT')
240
+ end
241
+ end
242
+
111
243
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mr. Eigenbart
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-07 00:00:00.000000000 Z
11
+ date: 2015-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.2.1
89
+ version: 1.5.0
90
90
  type: :runtime
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: 1.2.1
96
+ version: 1.5.0
97
97
  description: Rack middleware that provides authentication based on JSON Web Tokens.
98
98
  email:
99
99
  - eigenbart@gmail.com