jwt_sessions 1.0.2 → 1.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
  SHA1:
3
- metadata.gz: 143a1452f628f1d201801cc8b7b4855de56479fb
4
- data.tar.gz: e648fe573c4239e2359d808b5fb93e58d253cf59
3
+ metadata.gz: da93c28c622a3bac51b8f30be0190b0a3c79dda7
4
+ data.tar.gz: 29da1c13c80f4b89572d8f1c3ebe07dd031f775b
5
5
  SHA512:
6
- metadata.gz: d81c0bda06caebed8b38ca9649de98c3e5680859beb7059fd5f0534239f1aeb5b859c0e6f0582bb4585de44b7eef83136fa735d1ac2f7fa6107949e82dd777bb
7
- data.tar.gz: 7e717dc3a0326c81239d1ce12937182bcc5f7d59df884f9eb4e7513f7a398b8c42984b97865e8bdc6f1a3efc75e8b8c96225b04ff76c64adf44f95508cdc57e7
6
+ metadata.gz: 4a21622dd516292d881f87a0b22f140b8dc7c17be838b200cfa7ccbcbb8a1a55a7e7bd075f3ea49982c06811a24fdda721f7625f3b821e4dfeff9583311942a2
7
+ data.tar.gz: b5897c5ef7e0a3be5db1dcc67df71fd0eb56f4a5f3ee5008782c881b006a34e139be045e6a30e7632f5231bf425c62de3b62b150a9e92895befa522802ef346b
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # jwt_sessions
2
2
  [![Gem Version](https://badge.fury.io/rb/jwt_sessions.svg)](https://badge.fury.io/rb/jwt_sessions)
3
3
  [![Maintainability](https://api.codeclimate.com/v1/badges/53de11b8334933b1c0ef/maintainability)](https://codeclimate.com/github/tuwukee/jwt_sessions/maintainability)
4
+ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c86efdfca81448919ec3e1c1e48fc152)](https://www.codacy.com/app/tuwukee/jwt_sessions?utm_source=github.com&utm_medium=referral&utm_content=tuwukee/jwt_sessions&utm_campaign=Badge_Grade)
4
5
  [![Build Status](https://travis-ci.org/tuwukee/jwt_sessions.svg?branch=master)](https://travis-ci.org/tuwukee/jwt_sessions)
5
6
 
6
7
  XSS/CSRF safe JWT auth designed for SPA
@@ -77,9 +78,18 @@ Specify an encryption key for JSON Web Tokens in `config/initializers/jwt_sessio
77
78
  It's adviced to store the key itself within the app secrets.
78
79
 
79
80
  ```ruby
81
+ JWTSessions.algorithm = 'HS256'
80
82
  JWTSessions.encryption_key = Rails.application.secrets.secret_jwt_encryption_key
81
83
  ```
82
84
 
85
+ Most of the encryption algorithms require private and public keys to sign a token, yet HMAC only require a single key, so you can use a shortcat `encryotion_key` to sign the token. For other algorithms you must specify a private and public keys separately.
86
+
87
+ ```ruby
88
+ JWTSessions.algorithm = 'RS256'
89
+ JWTSessions.private_key = OpenSSL::PKey::RSA.generate(2048)
90
+ JWTSessions.public_key = JWTSessions.private_key.public_key
91
+ ```
92
+
83
93
  Generate access/refresh/csrf tokens with a custom payload. \
84
94
  The payload will be available in the controllers once the access (or refresh) token is authorized. \
85
95
  Access/refresh tokens contain expiration time in their payload. Yet expiration times are also added to the output just in case.
@@ -290,9 +300,46 @@ JWTSessions.algorithm = 'HS256'
290
300
  You need to specify a secret to use for HMAC, this setting doesn't have a default value.
291
301
 
292
302
  ```ruby
293
- JWTSessions.secret = 'secret'
303
+ JWTSessions.encryption_key = 'secret'
304
+ ```
305
+
306
+ If you are using another algorithm like RSA/ECDSA/EDDSA you should specify private and public keys.
307
+
308
+ ```ruby
309
+ JWTSessions.private_key = 'abcd'
310
+ JWTSessions.public_key = 'efjh'
311
+ ```
312
+
313
+ NOTE: ED25519 and HS512256 require rbnacl installation in order to make it work.
314
+
315
+ jwt_sessions only uses `exp` claim by default when it decodes tokens, you can specify which additional claims to use by
316
+ setting `jwt_options`. You can also specify leeway to account for clock skew.
317
+
318
+ ```ruby
319
+ JWTSessions.jwt_options.verify_iss = true
320
+ JWTSessions.jwt_options.verify_sub = true
321
+ JWTSessions.jwt_options.verify_iat = true
322
+ JWTSessions.jwt_options.verify_aud = true
323
+ JWTSessions.jwt_options.leeway = 30 # seconds
294
324
  ```
295
325
 
326
+ To pass options like `sub`, `aud`, `iss`, or leeways you should specify a method called `token_claims` in your controller.
327
+
328
+ ```ruby
329
+ class UsersController < ApplicationController
330
+ before_action :authorize_access_request!
331
+
332
+ def token_claims
333
+ {
334
+ aud: ['admin', 'staff'],
335
+ exp_leeway: 15 # will be used instead of default leeway only for exp claim
336
+ }
337
+ end
338
+ end
339
+ ```
340
+
341
+ Claims are also supported by `JWTSessions::Session`, you can pass `access_claims` and `refresh_claims` options in the initializer
342
+
296
343
  ##### Request headers and cookies names
297
344
 
298
345
  Default request headers/cookies names can be re-configured
@@ -307,7 +354,7 @@ JWTSessions.csrf_header = 'X-CSRF-Token'
307
354
 
308
355
  ##### Expiration time
309
356
 
310
- Acces token must have a short life span, while refresh tokens can be stored for a longer time period
357
+ Access token must have a short life span, while refresh tokens can be stored for a longer time period
311
358
 
312
359
  ```ruby
313
360
  JWTSessions.access_exp_time = 3600 # 1 hour in seconds
@@ -341,17 +388,14 @@ session.refresh(refresh_token) { |refresh_token_uid, access_token_expiration| ..
341
388
 
342
389
  ## TODO
343
390
 
344
- Ability to specify public and private keys for RSA/EDCSA/EDDSA, there are no default values for keys. \
345
- You can use instructions from [ruby-jwt](https://github.com/jwt/ruby-jwt) to generate keys corresponding keys.
346
-
347
- ```ruby
348
- JWTSessions.private_key = 'private_key'
349
- JWTSessions.public_key = 'public_key_for_private'
350
- ```
391
+ Session cleanup by uid or refresh token instance. \
392
+ Refresh token namespaces to allow centralized token cleanup per namespace (scenarios like password reset). \
393
+ Documentation for code.
351
394
 
352
395
  ## Contributing
353
396
 
354
- Fork & Pull Request
397
+ Fork & Pull Request \
398
+ RbNaCl and sodium cryptographic library are required for tests
355
399
 
356
400
  ## License
357
401
 
@@ -14,7 +14,8 @@ module JWTSessions
14
14
  rescue Errors::Unauthorized
15
15
  cookie_based_auth(token_type)
16
16
  end
17
- invalid_authorization unless Token.valid_payload?(payload)
17
+ # triggers token decode and jwt claim checks
18
+ payload
18
19
  check_csrf(token_type)
19
20
  end
20
21
  end
@@ -83,7 +84,8 @@ module JWTSessions
83
84
  end
84
85
 
85
86
  def payload
86
- @_payload ||= Token.decode(found_token).first
87
+ claims = respond_to?(:token_claims) ? token_claims : {}
88
+ @_payload ||= Token.decode(found_token, claims).first
87
89
  end
88
90
  end
89
91
  end
@@ -9,6 +9,8 @@ module JWTSessions
9
9
  @store = options.fetch(:store, JWTSessions.token_store)
10
10
  @refresh_payload = options.fetch(:refresh_payload, {})
11
11
  @payload = options.fetch(:payload, {})
12
+ @access_claims = options.fetch(:access_claims, {})
13
+ @refresh_claims = options.fetch(:refresh_claims, {})
12
14
  end
13
15
 
14
16
  def login
@@ -60,17 +62,17 @@ module JWTSessions
60
62
  end
61
63
 
62
64
  def access_token_data(token)
63
- uid = token_uid(token, :access)
65
+ uid = token_uid(token, :access, @access_claims)
64
66
  store.fetch_access(uid)
65
67
  end
66
68
 
67
69
  def refresh_token_data(token)
68
- uid = token_uid(token, :refresh)
70
+ uid = token_uid(token, :refresh, @refresh_claims)
69
71
  retrieve_refresh_token(uid)
70
72
  end
71
73
 
72
- def token_uid(token, type)
73
- token_payload = JWTSessions::Token.decode(token).first
74
+ def token_uid(token, type, claims)
75
+ token_payload = JWTSessions::Token.decode(token, claims).first
74
76
  uid = token_payload.fetch('uid', nil)
75
77
  if uid.nil?
76
78
  message = "#{type.to_s.capitalize} token payload does not contain token uid"
@@ -7,30 +7,21 @@ module JWTSessions
7
7
  class << self
8
8
  def encode(payload)
9
9
  exp_payload = meta.merge(payload)
10
- JWT.encode(exp_payload, JWTSessions.encryption_key, JWTSessions.algorithm)
10
+ JWT.encode(exp_payload, JWTSessions.private_key, JWTSessions.algorithm)
11
11
  end
12
12
 
13
- def decode(token)
14
- JWT.decode(token, JWTSessions.encryption_key, true, { algorithm: JWTSessions.algorithm, verify_expiration: false })
13
+ def decode(token, claims = {})
14
+ decode_options = { algorithm: JWTSessions.algorithm }.merge(JWTSessions.jwt_options.to_h).merge(claims)
15
+ JWT.decode(token, JWTSessions.public_key, JWTSessions.validate?, decode_options)
15
16
  rescue JWT::DecodeError => e
16
17
  raise Errors::Unauthorized, e.message
17
18
  rescue StandardError
18
19
  raise Errors::Unauthorized, 'could not decode a token'
19
20
  end
20
21
 
21
- def valid_payload?(payload)
22
- !expired?(payload)
23
- end
24
-
25
22
  def meta
26
23
  { exp: JWTSessions.access_expiration }
27
24
  end
28
-
29
- def expired?(payload)
30
- Time.at(payload['exp']) < Time.now
31
- rescue StandardError
32
- raise Errors::Unauthorized, 'invalid payload expiration time'
33
- end
34
25
  end
35
26
  end
36
27
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWTSessions
4
- VERSION = '1.0.2'
4
+ VERSION = '1.1.0'
5
5
  end
data/lib/jwt_sessions.rb CHANGED
@@ -18,6 +18,10 @@ module JWTSessions
18
18
 
19
19
  attr_writer :token_store
20
20
 
21
+ NONE = 'none'
22
+
23
+ JWTOptions = Struct.new(*JWT::DefaultOptions::DEFAULT_OPTIONS.keys)
24
+
21
25
  DEFAULT_SETTINGS_KEYS = %i[access_cookie
22
26
  access_exp_time
23
27
  access_header
@@ -30,19 +34,19 @@ module JWTSessions
30
34
  refresh_exp_time
31
35
  refresh_header
32
36
  token_prefix].freeze
33
- DEFAULT_REDIS_HOST = '127.0.0.1'
34
- DEFAULT_REDIS_PORT = '6379'
35
- DEFAULT_REDIS_DB_NAME = 'jwtokens'
36
- DEFAULT_TOKEN_PREFIX = 'jwt_'
37
- DEFAULT_ALGORITHM = 'HS256'
38
- DEFAULT_ACCESS_EXP_TIME = 3600 # 1 hour in seconds
39
- DEFAULT_REFRESH_EXP_TIME = 604800 # 1 week in seconds
40
- DEFAULT_ACCESS_COOKIE = 'jwt_access'
41
- DEFAULT_ACCESS_HEADER = 'Authorization'
42
- DEFAULT_REFRESH_COOKIE = 'jwt_refresh'
43
- DEFAULT_REFRESH_HEADER = 'X-Refresh-Token'
44
- DEFAULT_CSRF_HEADER = 'X-CSRF-Token'
45
37
 
38
+ DEFAULT_REDIS_HOST = '127.0.0.1'
39
+ DEFAULT_REDIS_PORT = '6379'
40
+ DEFAULT_REDIS_DB_NAME = 'jwtokens'
41
+ DEFAULT_TOKEN_PREFIX = 'jwt_'
42
+ DEFAULT_ALGORITHM = 'HS256'
43
+ DEFAULT_ACCESS_EXP_TIME = 3600 # 1 hour in seconds
44
+ DEFAULT_REFRESH_EXP_TIME = 604800 # 1 week in seconds
45
+ DEFAULT_ACCESS_COOKIE = 'jwt_access'
46
+ DEFAULT_ACCESS_HEADER = 'Authorization'
47
+ DEFAULT_REFRESH_COOKIE = 'jwt_refresh'
48
+ DEFAULT_REFRESH_HEADER = 'X-Refresh-Token'
49
+ DEFAULT_CSRF_HEADER = 'X-CSRF-Token'
46
50
 
47
51
  DEFAULT_SETTINGS_KEYS.each do |setting|
48
52
  var_name = :"@#{setting}"
@@ -61,13 +65,41 @@ module JWTSessions
61
65
  end
62
66
  end
63
67
 
68
+ def jwt_options
69
+ @jwt_options ||= JWTOptions.new(*JWT::DefaultOptions::DEFAULT_OPTIONS.values)
70
+ end
71
+
72
+ def algorithm=(algo)
73
+ raise Errors::Malconfigured, "algorithm #{algo} is not supported" unless supported_algos.include?(algo)
74
+ @algorithm = algo
75
+ end
76
+
64
77
  def token_store
65
78
  RedisTokenStore.instance(redis_host, redis_port, redis_db_name, token_prefix)
66
79
  end
67
80
 
68
- def encryption_key
69
- raise Errors::Malconfigured, 'encryption_key is not specified' unless @encryption_key
70
- @encryption_key
81
+ def validate?
82
+ algorithm != NONE
83
+ end
84
+
85
+ [:public_key, :private_key].each do |key|
86
+ var_name = :"@#{key}"
87
+ define_method("#{key}") do
88
+ return nil if algorithm == NONE
89
+ var = instance_variable_get(var_name)
90
+ raise Errors::Malconfigured, "#{key} is not specified" unless var
91
+ var
92
+ end
93
+
94
+ define_method("#{key}=") do |val|
95
+ instance_variable_set(var_name, val)
96
+ end
97
+ end
98
+
99
+ # should be used for hmac only
100
+ def encryption_key=(key)
101
+ @public_key = key
102
+ @private_key = key
71
103
  end
72
104
 
73
105
  def access_expiration
@@ -78,9 +110,6 @@ module JWTSessions
78
110
  Time.now.to_i + refresh_exp_time.to_i
79
111
  end
80
112
 
81
- def encryption_key=(key)
82
- @encryption_key = key
83
- end
84
113
 
85
114
  def header_by(token_type)
86
115
  send("#{token_type}_header")
@@ -89,4 +118,12 @@ module JWTSessions
89
118
  def cookie_by(token_type)
90
119
  send("#{token_type}_cookie")
91
120
  end
121
+
122
+ private
123
+
124
+ def supported_algos
125
+ # TODO once ECDSA is fixed in ruby-jwt it can be added to the list of algos just the same way others are added
126
+ algos = JWT::Algos.constants - [:Unsupported, :Ecdsa]
127
+ algos.map { |algo| JWT::Algos.const_get(algo)::SUPPORTED }.flatten + [NONE, *JWT::Algos::Ecdsa::SUPPORTED.split(' ')]
128
+ end
92
129
  end
@@ -39,10 +39,10 @@ class TestSession < Minitest::Test
39
39
  JWTSessions.access_exp_time = 0
40
40
  @session = JWTSessions::Session.new(payload: payload)
41
41
  @tokens = session.login
42
+ JWTSessions.access_exp_time = 3600
42
43
  refreshed_tokens = session.refresh(tokens[:refresh]) do
43
44
  raise JWTSessions::Errors::Unauthorized
44
45
  end
45
- JWTSessions.access_exp_time = 3600
46
46
  decoded_access = JWTSessions::Token.decode(refreshed_tokens[:access]).first
47
47
  assert_equal EXPECTED_KEYS, refreshed_tokens.keys.sort
48
48
  assert_equal payload[:test], decoded_access['test']
@@ -2,17 +2,128 @@
2
2
 
3
3
  require 'minitest/autorun'
4
4
  require 'jwt_sessions'
5
+ require 'pry'
6
+
7
+ nacl_supported_versions = {
8
+ 'ruby' => ['~> 2.2.6', '~> 2.3.0', '~> 2.4.2'],
9
+ 'jruby' => ['~> 9.1.6.0']
10
+ }.each_with_object([]) do |(platform, versions), acc|
11
+ acc.concat(versions.map { |version| Gem::Dependency.new(platform, version) })
12
+ end
13
+
14
+ nacl_supported = nacl_supported_versions.any? { |version| version.match?(RUBY_ENGINE, RUBY_VERSION) }
15
+
16
+ $uses_nacl = !!(defined?(RbNaCl) || require('rbnacl') if nacl_supported)
5
17
 
6
18
  class TestToken < Minitest::Test
7
19
  attr_reader :payload
8
20
 
9
21
  def setup
10
- JWTSessions.encryption_key = 'super secret'
11
22
  @payload = { 'user_id' => 1, 'secret' => 'mystery' }
23
+ JWTSessions.encryption_key = 'abcdefghijklmnopqrstuvwxyzABCDEF'
24
+ end
25
+
26
+ def teardown
27
+ JWTSessions.algorithm = JWTSessions::DEFAULT_ALGORITHM
28
+ JWTSessions.instance_variable_set(:'@jwt_options', JWTSessions::JWTOptions.new(*JWT::DefaultOptions::DEFAULT_OPTIONS.values))
29
+ end
30
+
31
+ def test_rsa_token_decode
32
+ JWTSessions.algorithm = 'RS256'
33
+ JWTSessions.private_key = OpenSSL::PKey::RSA.generate 2048
34
+ JWTSessions.public_key = JWTSessions.private_key.public_key
35
+
36
+ token = JWTSessions::Token.encode(payload)
37
+ decoded = JWTSessions::Token.decode(token).first
38
+ assert_equal payload['user_id'], decoded['user_id']
39
+ assert_equal payload['secret'], decoded['secret']
40
+ end
41
+
42
+ def test_eddsa_token_decode
43
+ skip unless $uses_nacl
44
+ JWTSessions.algorithm = 'ED25519'
45
+ JWTSessions.private_key = ::RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF')
46
+ JWTSessions.public_key = JWTSessions.private_key.verify_key
47
+
48
+ token = JWTSessions::Token.encode(payload)
49
+ decoded = JWTSessions::Token.decode(token).first
50
+ assert_equal payload['user_id'], decoded['user_id']
51
+ assert_equal payload['secret'], decoded['secret']
52
+ end
53
+
54
+ def test_ecdsa_token_decode
55
+ JWTSessions.algorithm = 'ES256'
56
+ JWTSessions.private_key = OpenSSL::PKey::EC.new 'prime256v1'
57
+ JWTSessions.private_key.generate_key
58
+ JWTSessions.public_key = OpenSSL::PKey::EC.new JWTSessions.private_key
59
+ JWTSessions.public_key.private_key = nil
60
+
61
+ token = JWTSessions::Token.encode(payload)
62
+ decoded = JWTSessions::Token.decode(token).first
63
+ assert_equal payload['user_id'], decoded['user_id']
64
+ assert_equal payload['secret'], decoded['secret']
65
+ end
66
+
67
+ def test_hmac_token_decode
68
+ JWTSessions.encryption_key = 'abcdefghijklmnopqrstuvwxyzABCDEF'
69
+ token = JWTSessions::Token.encode(payload)
70
+ decoded = JWTSessions::Token.decode(token).first
71
+ assert_equal payload['user_id'], decoded['user_id']
72
+ assert_equal payload['secret'], decoded['secret']
73
+ end
74
+
75
+ def test_token_sub_claim
76
+ JWTSessions.encryption_key = 'abcdefghijklmnopqrstuvwxyzABCDEF'
77
+ JWTSessions.jwt_options.verify_sub = true
78
+ token = JWTSessions::Token.encode(payload.merge(sub: 'subject'))
79
+ decoded = JWTSessions::Token.decode(token, { sub: 'subject' }).first
80
+ assert_equal payload['user_id'], decoded['user_id']
81
+ assert_equal payload['secret'], decoded['secret']
82
+ assert_raises JWTSessions::Errors::Unauthorized do
83
+ JWTSessions::Token.decode(token, { sub: 'different subject' })
84
+ end
85
+ end
86
+
87
+ def test_token_iss_claim
88
+ JWTSessions.encryption_key = 'abcdefghijklmnopqrstuvwxyzABCDEF'
89
+ JWTSessions.jwt_options.verify_iss = true
90
+ token = JWTSessions::Token.encode(payload.merge(iss: 'Me'))
91
+ decoded = JWTSessions::Token.decode(token, { iss: 'Me' }).first
92
+ assert_equal payload['user_id'], decoded['user_id']
93
+ assert_equal payload['secret'], decoded['secret']
94
+ assert_raises JWTSessions::Errors::Unauthorized do
95
+ JWTSessions::Token.decode(token, { iss: 'Not Me' })
96
+ end
97
+ end
98
+
99
+ def test_token_aud_claim
100
+ JWTSessions.encryption_key = 'abcdefghijklmnopqrstuvwxyzABCDEF'
101
+ JWTSessions.jwt_options.verify_aud = true
102
+ token = JWTSessions::Token.encode(payload.merge(aud: ['young', 'old']))
103
+ decoded = JWTSessions::Token.decode(token, { aud: ['young'] }).first
104
+ assert_equal payload['user_id'], decoded['user_id']
105
+ assert_equal payload['secret'], decoded['secret']
106
+ assert_raises JWTSessions::Errors::Unauthorized do
107
+ JWTSessions::Token.decode(token, { aud: ['adult'] })
108
+ end
109
+ end
110
+
111
+ def test_token_leeway_decode
112
+ JWTSessions.encryption_key = 'abcdefghijklmnopqrstuvwxyzABCDEF'
113
+ JWTSessions.jwt_options.leeway = 50
114
+ token = JWTSessions::Token.encode(payload.merge(exp: Time.now.to_i - 20))
115
+ decoded = JWTSessions::Token.decode(token).first
116
+ assert_equal payload['user_id'], decoded['user_id']
117
+ assert_equal payload['secret'], decoded['secret']
118
+ token = JWTSessions::Token.encode(payload.merge(exp: Time.now.to_i - 100))
119
+ assert_raises JWTSessions::Errors::Unauthorized do
120
+ JWTSessions::Token.decode(token)
121
+ end
12
122
  end
13
123
 
14
- def test_valid_token_decode
15
- token = JWTSessions::Token.encode(payload)
124
+ def test_none_token_decode
125
+ JWTSessions.algorithm = JWTSessions::NONE
126
+ token = JWTSessions::Token.encode(payload)
16
127
  decoded = JWTSessions::Token.decode(token).first
17
128
  assert_equal payload['user_id'], decoded['user_id']
18
129
  assert_equal payload['secret'], decoded['secret']
@@ -31,12 +142,9 @@ class TestToken < Minitest::Test
31
142
  end
32
143
 
33
144
  def test_payload_exp_time
145
+ token = JWTSessions::Token.encode(payload.merge(exp: Time.now.to_i - (3600 * 24)))
34
146
  assert_raises JWTSessions::Errors::Unauthorized do
35
- JWTSessions::Token.valid_payload?(payload)
147
+ JWTSessions::Token.decode(token)
36
148
  end
37
- payload['exp'] = Time.now - (3600 * 24)
38
- assert_equal false, JWTSessions::Token.valid_payload?(payload)
39
- payload['exp'] = Time.now + (3600 * 24)
40
- assert_equal true, JWTSessions::Token.valid_payload?(payload)
41
149
  end
42
150
  end
@@ -21,7 +21,11 @@ class TestJWTSessions < Minitest::Test
21
21
  def test_encryption_key
22
22
  JWTSessions.encryption_key = nil
23
23
  assert_raises JWTSessions::Errors::Malconfigured do
24
- JWTSessions.encryption_key
24
+ JWTSessions.private_key
25
+ end
26
+
27
+ assert_raises JWTSessions::Errors::Malconfigured do
28
+ JWTSessions.public_key
25
29
  end
26
30
  end
27
31
 
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt_sessions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yulia Oletskaya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-19 00:00:00.000000000 Z
11
+ date: 2018-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.4'
19
+ version: '2.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.4'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: redis
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '10.0'
89
+ version: '12.3'
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: '10.0'
96
+ version: '12.3'
97
97
  description: XSS/CSRF safe JWT auth designed for SPA
98
98
  email: yulia.oletskaya@gmail.com
99
99
  executables: []