rack-jwt 0.1.1 → 0.2.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
  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