jwt_sessions 1.0.1 → 1.0.2
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 +4 -4
- data/README.md +33 -4
- data/lib/jwt_sessions/access_token.rb +2 -1
- data/lib/jwt_sessions/session.rb +10 -2
- data/lib/jwt_sessions/version.rb +1 -1
- data/test/units/jwt_sessions/test_access_token.rb +30 -0
- data/test/units/jwt_sessions/test_refresh_token.rb +1 -1
- data/test/units/jwt_sessions/test_session.rb +3 -3
- data/test/units/jwt_sessions/test_token.rb +5 -3
- metadata +46 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 143a1452f628f1d201801cc8b7b4855de56479fb
|
4
|
+
data.tar.gz: e648fe573c4239e2359d808b5fb93e58d253cf59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d81c0bda06caebed8b38ca9649de98c3e5680859beb7059fd5f0534239f1aeb5b859c0e6f0582bb4585de44b7eef83136fa735d1ac2f7fa6107949e82dd777bb
|
7
|
+
data.tar.gz: 7e717dc3a0326c81239d1ce12937182bcc5f7d59df884f9eb4e7513f7a398b8c42984b97865e8bdc6f1a3efc75e8b8c96225b04ff76c64adf44f95508cdc57e7
|
data/README.md
CHANGED
@@ -1,8 +1,29 @@
|
|
1
1
|
# jwt_sessions
|
2
2
|
[](https://badge.fury.io/rb/jwt_sessions)
|
3
|
+
[](https://codeclimate.com/github/tuwukee/jwt_sessions/maintainability)
|
4
|
+
[](https://travis-ci.org/tuwukee/jwt_sessions)
|
3
5
|
|
4
6
|
XSS/CSRF safe JWT auth designed for SPA
|
5
7
|
|
8
|
+
## Table of Contents
|
9
|
+
|
10
|
+
- [Synopsis](#synopsis)
|
11
|
+
- [Installation](#installation)
|
12
|
+
- [Getting Started](#getting-started)
|
13
|
+
* [Rails integration](#rails-integration)
|
14
|
+
* [Non-Rails usage](#non-rails-usage)
|
15
|
+
- [Configuration](#configuration)
|
16
|
+
+ [Redis](#redis)
|
17
|
+
+ [JWT encryption](#jwt-encryption)
|
18
|
+
+ [Request headers and cookies names](#request-headers-and-cookies-names)
|
19
|
+
+ [Expiration time](#expiration-time)
|
20
|
+
+ [CSRF and cookies](#csrf-and-cookies)
|
21
|
+
+ [Refresh token hijack protection](#refresh-token-hijack-protection)
|
22
|
+
- [Examples](#examples)
|
23
|
+
- [TODO](#todo)
|
24
|
+
- [Contributing](#contributing)
|
25
|
+
- [License](#license)
|
26
|
+
|
6
27
|
## Synopsis
|
7
28
|
|
8
29
|
Main goal of this gem is to provide configurable, manageable, and safe stateful sessions based on JSON Web Tokens.
|
@@ -60,7 +81,8 @@ JWTSessions.encryption_key = Rails.application.secrets.secret_jwt_encryption_key
|
|
60
81
|
```
|
61
82
|
|
62
83
|
Generate access/refresh/csrf tokens with a custom payload. \
|
63
|
-
The payload will be available in the controllers once the access (or refresh) token is authorized.
|
84
|
+
The payload will be available in the controllers once the access (or refresh) token is authorized. \
|
85
|
+
Access/refresh tokens contain expiration time in their payload. Yet expiration times are also added to the output just in case.
|
64
86
|
|
65
87
|
```ruby
|
66
88
|
> payload = { user_id: user.id }
|
@@ -72,7 +94,9 @@ The payload will be available in the controllers once the access (or refresh) to
|
|
72
94
|
> session.login
|
73
95
|
=> {:csrf=>"BmhxDRW5NAEIx...",
|
74
96
|
:access=>"eyJhbGciOiJIUzI1NiJ9...",
|
75
|
-
:
|
97
|
+
:access_expires_at=>"..."
|
98
|
+
:refresh=>"eyJhbGciOiJIUzI1NiJ9...",
|
99
|
+
:refresh_expires_at=>"..."}
|
76
100
|
```
|
77
101
|
|
78
102
|
You can build login controller to receive access, refresh and csrf tokens in exchange for user's login/password. \
|
@@ -185,7 +209,7 @@ def request_method
|
|
185
209
|
end
|
186
210
|
```
|
187
211
|
|
188
|
-
Example Sinatra app.
|
212
|
+
Example Sinatra app. \
|
189
213
|
NOTE: Since rack updates HTTP headers by using `HTTP_` prefix, upcasing and using underscores for sake of simplicity JWTSessions tokens header names are converted to rack-style in this example.
|
190
214
|
|
191
215
|
```ruby
|
@@ -231,7 +255,7 @@ class SimpleApp < Sinatra::Base
|
|
231
255
|
session.refresh(found_token).to_json
|
232
256
|
end
|
233
257
|
|
234
|
-
#
|
258
|
+
# GET /payload
|
235
259
|
# authorization: Bearer ...
|
236
260
|
get '/payload' do
|
237
261
|
authorize_access_request!
|
@@ -310,6 +334,11 @@ session = JwtSessions::Session.new(payload: payload)
|
|
310
334
|
session.refresh(refresh_token) { |refresh_token_uid, access_token_expiration| ... }
|
311
335
|
```
|
312
336
|
|
337
|
+
## Examples
|
338
|
+
|
339
|
+
[Rails API](test/support/dummy_api) \
|
340
|
+
[Sinatra API](test/support/dummy_sinatra_api)
|
341
|
+
|
313
342
|
## TODO
|
314
343
|
|
315
344
|
Ability to specify public and private keys for RSA/EDCSA/EDDSA, there are no default values for keys. \
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module JWTSessions
|
2
2
|
class AccessToken
|
3
|
-
attr_reader :token, :payload, :uid, :expiration, :csrf
|
3
|
+
attr_reader :token, :payload, :uid, :expiration, :csrf, :store
|
4
4
|
|
5
5
|
def initialize(csrf, payload, store, uid = SecureRandom.uuid, expiration = JWTSessions.access_expiration)
|
6
6
|
@csrf = csrf
|
7
7
|
@uid = uid
|
8
8
|
@expiration = expiration
|
9
9
|
@payload = payload
|
10
|
+
@store = store
|
10
11
|
@token = Token.encode(payload.merge(uid: uid, exp: expiration.to_i))
|
11
12
|
end
|
12
13
|
|
data/lib/jwt_sessions/session.rb
CHANGED
@@ -84,7 +84,11 @@ module JWTSessions
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def tokens_hash
|
87
|
-
{ csrf: csrf_token,
|
87
|
+
{ csrf: csrf_token,
|
88
|
+
access: access_token,
|
89
|
+
access_expires_at: Time.at(@_access.expiration.to_i),
|
90
|
+
refresh: refresh_token,
|
91
|
+
refresh_expires_at: Time.at(@_refresh.expiration.to_i) }
|
88
92
|
end
|
89
93
|
|
90
94
|
def check_refresh_on_time
|
@@ -111,7 +115,11 @@ module JWTSessions
|
|
111
115
|
end
|
112
116
|
|
113
117
|
def create_refresh_token
|
114
|
-
@_refresh = RefreshToken.create(@_csrf.encoded,
|
118
|
+
@_refresh = RefreshToken.create(@_csrf.encoded,
|
119
|
+
@_access.uid,
|
120
|
+
@_access.expiration,
|
121
|
+
store,
|
122
|
+
@refresh_payload)
|
115
123
|
@refresh_token = @_refresh.token
|
116
124
|
end
|
117
125
|
|
data/lib/jwt_sessions/version.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'jwt_sessions'
|
5
|
+
|
6
|
+
class TestAccessToken < Minitest::Test
|
7
|
+
attr_reader :access_token, :uid
|
8
|
+
|
9
|
+
def setup
|
10
|
+
JWTSessions.encryption_key = 'secret key'
|
11
|
+
@payload = { user_id: 1 }
|
12
|
+
@csrf = JWTSessions::CSRFToken.new
|
13
|
+
@uid = SecureRandom.uuid
|
14
|
+
@access_token = JWTSessions::AccessToken.create(@csrf.encoded,
|
15
|
+
@payload,
|
16
|
+
JWTSessions.token_store)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_csrf
|
20
|
+
token = JWTSessions.token_store.fetch_access(access_token.uid)
|
21
|
+
assert_equal token[:csrf], access_token.csrf
|
22
|
+
access_token.destroy
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_destroy
|
26
|
+
JWTSessions::AccessToken.destroy(access_token.uid, JWTSessions.token_store)
|
27
|
+
token = JWTSessions.token_store.fetch_access(access_token.uid)
|
28
|
+
assert_equal({}, token)
|
29
|
+
end
|
30
|
+
end
|
@@ -7,7 +7,7 @@ class TestRefreshToken < Minitest::Test
|
|
7
7
|
attr_reader :csrf, :token, :access_uid
|
8
8
|
|
9
9
|
def setup
|
10
|
-
JWTSessions.encryption_key = '
|
10
|
+
JWTSessions.encryption_key = 'secure encryption'
|
11
11
|
@access_uid = SecureRandom.uuid
|
12
12
|
@csrf = JWTSessions::CSRFToken.new
|
13
13
|
@token = JWTSessions::RefreshToken.create(@csrf.encoded,
|
@@ -5,11 +5,11 @@ require 'jwt_sessions'
|
|
5
5
|
|
6
6
|
class TestSession < Minitest::Test
|
7
7
|
attr_reader :session, :payload, :tokens
|
8
|
-
EXPECTED_KEYS = [
|
8
|
+
EXPECTED_KEYS = %i[access access_expires_at csrf refresh refresh_expires_at].freeze
|
9
9
|
|
10
10
|
def setup
|
11
|
-
JWTSessions.encryption_key = '
|
12
|
-
@payload = { test: '
|
11
|
+
JWTSessions.encryption_key = 'encrypted'
|
12
|
+
@payload = { test: 'secret' }
|
13
13
|
@session = JWTSessions::Session.new(payload: payload)
|
14
14
|
@tokens = session.login
|
15
15
|
end
|
@@ -7,13 +7,15 @@ class TestToken < Minitest::Test
|
|
7
7
|
attr_reader :payload
|
8
8
|
|
9
9
|
def setup
|
10
|
-
JWTSessions.encryption_key = '
|
11
|
-
@payload = { 'user_id' => 1 }
|
10
|
+
JWTSessions.encryption_key = 'super secret'
|
11
|
+
@payload = { 'user_id' => 1, 'secret' => 'mystery' }
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_valid_token_decode
|
15
15
|
token = JWTSessions::Token.encode(payload)
|
16
|
-
|
16
|
+
decoded = JWTSessions::Token.decode(token).first
|
17
|
+
assert_equal payload['user_id'], decoded['user_id']
|
18
|
+
assert_equal payload['secret'], decoded['secret']
|
17
19
|
end
|
18
20
|
|
19
21
|
def test_invalid_token_decode
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwt_sessions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
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-
|
11
|
+
date: 2018-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.16'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.16'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.11'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.11'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: pry
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +80,20 @@ dependencies:
|
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
82
|
version: '0.11'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
55
97
|
description: XSS/CSRF safe JWT auth designed for SPA
|
56
98
|
email: yulia.oletskaya@gmail.com
|
57
99
|
executables: []
|
@@ -71,6 +113,7 @@ files:
|
|
71
113
|
- lib/jwt_sessions/session.rb
|
72
114
|
- lib/jwt_sessions/token.rb
|
73
115
|
- lib/jwt_sessions/version.rb
|
116
|
+
- test/units/jwt_sessions/test_access_token.rb
|
74
117
|
- test/units/jwt_sessions/test_csrf_token.rb
|
75
118
|
- test/units/jwt_sessions/test_refresh_token.rb
|
76
119
|
- test/units/jwt_sessions/test_session.rb
|
@@ -102,6 +145,7 @@ specification_version: 4
|
|
102
145
|
summary: JWT Sessions
|
103
146
|
test_files:
|
104
147
|
- test/units/test_jwt_sessions.rb
|
148
|
+
- test/units/jwt_sessions/test_access_token.rb
|
105
149
|
- test/units/jwt_sessions/test_csrf_token.rb
|
106
150
|
- test/units/jwt_sessions/test_refresh_token.rb
|
107
151
|
- test/units/jwt_sessions/test_session.rb
|