credible 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +29 -11
- data/app/views/credible/sessions/_session.json.jbuilder +3 -1
- data/app/views/credible/users/_user.json.jbuilder +6 -1
- data/config/initializers/warden.rb +40 -4
- data/config/routes.rb +8 -0
- data/lib/credible/controllers/sessions_controller.rb +19 -1
- data/lib/credible/session.rb +22 -4
- data/lib/credible/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36d4cd634fa34562978e37d5a84169812678c28109d09c58238cb8c5bc2338d5
|
4
|
+
data.tar.gz: edc9471b968557985508ed60f49ae905390b3167d120497b3ea272faed0b423a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 263ef8576aae2c0b1aaad9d1e5710c2eca33e5812accbe1a5d19827b37782bb3a8109ba5a91f77a41fc16a41834d5c4d040358be44017836ed9a22c54ffe6c0c
|
7
|
+
data.tar.gz: f23153d8e705f201acba1ff85c31016f2e1a1e9076016a66083ef8fb7da21a740c0bd2d5031ec4cf4e881ed0f352e3ac662a4592f599f9f70b7960ba7ab56ae9
|
data/README.md
CHANGED
@@ -1,18 +1,22 @@
|
|
1
|
-
|
1
|
+
<h1 id="credible" align="center">Credible</h1>
|
2
2
|
|
3
|
-
|
3
|
+
<p align="center"><strong>Credible</strong> | <a href="https://github.com/thombruce/credible-demo">Demo Repo</a> | <a href="https://github.com/thombruce/helvellyn">Helvellyn</a></p>
|
4
4
|
|
5
|
-
|
6
|
-
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/thombruce/credible/CI?logo=github)](https://github.com/thombruce/credible/actions)
|
7
|
-
[![Codecov](https://img.shields.io/codecov/c/github/thombruce/credible?logo=codecov)](https://codecov.io/gh/thombruce/credible)
|
8
|
-
[![GitHub issues](https://img.shields.io/github/issues-raw/thombruce/credible?logo=github)](https://github.com/thombruce/credible/issues)
|
5
|
+
<p align="center"><a href="https://www.patreon.com/thombruce"><img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patron"></a></p>
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
<p align="center"><a href="https://rubygems.org/gems/credible"><img src="https://img.shields.io/gem/v/credible?logo=rubygems" alt="Gem"></a>
|
8
|
+
<a href="https://github.com/thombruce/credible/actions"><img src="https://img.shields.io/github/workflow/status/thombruce/credible/CI?logo=github" alt="GitHub Workflow Status"></a>
|
9
|
+
<a href="https://codecov.io/gh/thombruce/credible"><img src="https://img.shields.io/codecov/c/github/thombruce/credible?logo=codecov" alt="Codecov"></a>
|
10
|
+
<a href="https://github.com/thombruce/credible/issues"><img src="https://img.shields.io/github/issues-raw/thombruce/credible?logo=github" alt="GitHub issues"></a></p>
|
14
11
|
|
15
|
-
|
12
|
+
<p align="center"><a href="MIT-LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
13
|
+
<a href="CONTRIBUTING.md"><img src="https://img.shields.io/badge/contributions-welcome-blue.svg" alt="Contributing"></a>
|
14
|
+
<a href="https://discord.gg/YMU87db"><img src="https://img.shields.io/discord/697123984231366716?color=7289da&label=chat&logo=discord" alt="Discord"></a></p>
|
15
|
+
|
16
|
+
<p align="center"><a href="CHANGELOG.md"><img src="https://img.shields.io/badge/Keep%20a%20Changelog-v1.1.0%20adopted-red.svg" alt="Changelog"></a>
|
17
|
+
<a href="CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v1.4%20adopted-ff69b4.svg" alt="Contributor Covenant"></a></p>
|
18
|
+
|
19
|
+
<p align="center">Credible was extracted from <a href="https://github.com/thombruce/helvellyn">thombruce/helvellyn</a> and is still a work in progress. The goal is to provide JWT and API token based authentication using <a href="https://github.com/wardencommunity/warden/">Warden</a> for Rails API applications.</p>
|
16
20
|
|
17
21
|
## Installation
|
18
22
|
|
@@ -73,6 +77,20 @@ class Session < ApplicationRecord
|
|
73
77
|
end
|
74
78
|
```
|
75
79
|
|
80
|
+
## Calling the API
|
81
|
+
|
82
|
+
To sign up and create a new user, send params in the form `{ user: { email: 'email@example.com', password: 'Pa$$word123!' } }` to `auth/signup` as a `POST` request. On success, this will return `{ access_token: '...', refresh_token: '...' }` that can be used to persist the user's session.
|
83
|
+
|
84
|
+
To sign in a user, send params in the form `{ session: { login: 'email@example.com', password: 'Pa$$word123!' } }` to `auth/login` as a `POST` request. On success, this will return `{ access_token: '...', refresh_token: '...' }` that can be used to persist the user's session.
|
85
|
+
|
86
|
+
To sign out a user, send an empty request to `auth/signout` as a `DELETE` request. On success, this will return no content. It will destroy the session in the database and invalidate any existing tokens. Note: If you are using the access token to authenticate the user on a separate server, it will still remain valid until its expiry.
|
87
|
+
|
88
|
+
To refresh an access token, send params in the form `{ refresh_token: '...' }` to `auth/refresh` as a `POST` request. On success, this will return `{ access_token: '...', refresh_token: '...' }` that can be used to continue the user's session. Note: This will also invalidate the refresh token used to renew the tokens, and provide a new refresh token for next use.
|
89
|
+
|
90
|
+
> **Be careful**
|
91
|
+
>
|
92
|
+
> Credible is still a work in progress and these routes will be subject to change. I'm thinking about keeping them around as sort of a "classic" mode, but I feel like more resource-oriented routes are also desirable. For example, I want to add a `/tokens` endpoint in place of the existing `/refresh` enpoint, because _refresh what?_ It's just more semantically correct.
|
93
|
+
|
76
94
|
## Mailers
|
77
95
|
|
78
96
|
To user Credible's in-built mailers, you must set a hostname for your application. A suitable setting for this in `config/environments/development.rb` might be:
|
@@ -1,5 +1,10 @@
|
|
1
1
|
json.extract! user, :id, :email, :created_at, :updated_at
|
2
2
|
|
3
|
-
|
3
|
+
if @session
|
4
|
+
json.access_token @session.access_token
|
5
|
+
json.jwt @session.access_token
|
6
|
+
|
7
|
+
json.refresh_token @session.refresh_token
|
8
|
+
end
|
4
9
|
|
5
10
|
json.url user_url(user, format: :json)
|
@@ -3,12 +3,13 @@ Rails.application.config.middleware.use Warden::Manager do |config|
|
|
3
3
|
|
4
4
|
config.default_scope = :session
|
5
5
|
|
6
|
-
config.scope_defaults :session, store: false, strategies: [:jwt, :api_token]
|
6
|
+
config.scope_defaults :session, store: false, strategies: [:jwt, :refresh, :api_token]
|
7
7
|
end
|
8
8
|
|
9
9
|
# TODO: See here for how Devise initializes Warden: https://github.com/heartcombo/devise/blob/715192a7709a4c02127afb067e66230061b82cf2/lib/devise/rails.rb
|
10
10
|
# It's also worth perusing the mention of 'warden' in the Devise repo. Interesting strategies at work.
|
11
11
|
|
12
|
+
# TODO: Change to :access_token, maybe maintain :jwt as alias
|
12
13
|
Warden::Strategies.add(:jwt) do
|
13
14
|
def valid?
|
14
15
|
env['HTTP_AUTHORIZATION']
|
@@ -25,14 +26,49 @@ Warden::Strategies.add(:jwt) do
|
|
25
26
|
jwt = header.gsub(pattern, '') if header && header.match(pattern)
|
26
27
|
token =
|
27
28
|
JWT.decode jwt, Rails.application.secrets.secret_key_base, true,
|
28
|
-
iss: Rails.application.class.module_parent_name,
|
29
|
-
|
29
|
+
iss: Rails.application.class.module_parent_name,
|
30
|
+
verify_iss: true, verify_iat: true, verify_expiration: true,
|
31
|
+
algorithm: 'HS256' # [1]
|
32
|
+
rescue JWT::InvalidIssuerError, JWT::InvalidIatError, JWT::ExpiredSignature
|
30
33
|
fail!('Could not authenticate')
|
31
34
|
end
|
32
35
|
|
33
36
|
session = ::Session.find(token[0]['data']['session_id'])
|
34
37
|
success!(session)
|
35
|
-
rescue ActiveRecord::RecordNotFound
|
38
|
+
rescue # ActiveRecord::RecordNotFound
|
39
|
+
fail!('Could not authenticate')
|
40
|
+
end
|
41
|
+
|
42
|
+
def store?
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Warden::Strategies.add(:refresh) do
|
48
|
+
def valid?
|
49
|
+
# params[:refresh_token]
|
50
|
+
env['action_dispatch.request.parameters']['refresh_token'] # https://github.com/wardencommunity/warden/issues/84
|
51
|
+
end
|
52
|
+
|
53
|
+
def env
|
54
|
+
request.env
|
55
|
+
end
|
56
|
+
|
57
|
+
def authenticate!
|
58
|
+
begin
|
59
|
+
jwt = env['action_dispatch.request.parameters']['refresh_token']
|
60
|
+
token =
|
61
|
+
JWT.decode jwt, Rails.application.secrets.secret_key_base, true,
|
62
|
+
iss: Rails.application.class.module_parent_name,
|
63
|
+
verify_iss: true, verify_iat: true, verify_expiration: true,
|
64
|
+
algorithm: 'HS256' # [1]
|
65
|
+
rescue JWT::InvalidIssuerError, JWT::InvalidIatError, JWT::ExpiredSignature
|
66
|
+
fail!('Could not authenticate')
|
67
|
+
end
|
68
|
+
|
69
|
+
session = ::Session.find(token[0]['data']['session_id'])
|
70
|
+
success!(session)
|
71
|
+
rescue # ActiveRecord::RecordNotFound
|
36
72
|
fail!('Could not authenticate')
|
37
73
|
end
|
38
74
|
|
data/config/routes.rb
CHANGED
@@ -2,12 +2,19 @@ Credible::Engine.routes.draw do
|
|
2
2
|
scope format: false, defaults: { format: 'json' } do
|
3
3
|
# /auth/login.json
|
4
4
|
post 'login', to: 'sessions#create'
|
5
|
+
|
6
|
+
# /auth/refresh.json
|
7
|
+
post 'refresh', to: 'sessions#refresh'
|
8
|
+
|
5
9
|
# /auth/reset_password.json
|
6
10
|
post 'reset_password', to: 'users#reset_password'
|
11
|
+
|
7
12
|
# /auth/signup.json
|
8
13
|
post 'signup', to: 'users#create'
|
14
|
+
|
9
15
|
# /auth/confirm.json
|
10
16
|
get 'confirm/:confirmation_token', to: 'users#confirm', as: :confirmation
|
17
|
+
|
11
18
|
# /auth/signout.json
|
12
19
|
delete 'signout', to: 'sessions#destroy'
|
13
20
|
|
@@ -15,6 +22,7 @@ Credible::Engine.routes.draw do
|
|
15
22
|
scope '/account' do
|
16
23
|
# /auth/account/sessions/*.json
|
17
24
|
resources :sessions, except: [:new, :create, :edit, :update]
|
25
|
+
|
18
26
|
# /auth/account/*.json
|
19
27
|
resource :user, path: '', except: [:new, :create]
|
20
28
|
end
|
@@ -5,7 +5,8 @@ module Credible
|
|
5
5
|
|
6
6
|
included do
|
7
7
|
before_action :set_session, only: [:show, :destroy]
|
8
|
-
skip_before_action :authenticate!, only: [:new, :create, :fail]
|
8
|
+
skip_before_action :authenticate!, only: [:new, :create, :refresh, :fail]
|
9
|
+
before_action :authenticate_with_refresh_token!, only: [:refresh]
|
9
10
|
# skip_after_action :verify_authorized, only: [:fail]
|
10
11
|
# TODO: Reevaluate authorization without Pundit
|
11
12
|
end
|
@@ -37,6 +38,19 @@ module Credible
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
# POST /refresh
|
42
|
+
# POST /refresh.json
|
43
|
+
def refresh
|
44
|
+
@session = ::Session.new(user: current_user)
|
45
|
+
|
46
|
+
if @session.save
|
47
|
+
current_session.destroy
|
48
|
+
render :show, status: :created, location: @session
|
49
|
+
else
|
50
|
+
render json: @session.errors, status: :unprocessable_entity
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
40
54
|
# DELETE /sessions/1
|
41
55
|
# DELETE /sessions/1.json
|
42
56
|
# DELETE /sessions/current
|
@@ -60,6 +74,10 @@ module Credible
|
|
60
74
|
def session_params
|
61
75
|
params.require(:session).permit(:login, :password)
|
62
76
|
end
|
77
|
+
|
78
|
+
def authenticate_with_refresh_token!
|
79
|
+
warden.authenticate!(:refresh)
|
80
|
+
end
|
63
81
|
end
|
64
82
|
end
|
65
83
|
end
|
data/lib/credible/session.rb
CHANGED
@@ -9,10 +9,22 @@ module Credible
|
|
9
9
|
|
10
10
|
has_secure_token
|
11
11
|
|
12
|
-
def
|
12
|
+
def access_token
|
13
13
|
payload = {
|
14
|
-
data:
|
15
|
-
iss: Rails.application.class.module_parent_name
|
14
|
+
data: access_token_data,
|
15
|
+
iss: Rails.application.class.module_parent_name,
|
16
|
+
iat: Time.now.to_i,
|
17
|
+
exp: Time.now.to_i + 4 * 3600
|
18
|
+
}
|
19
|
+
JWT.encode payload, Rails.application.secrets.secret_key_base, 'HS256' # [1]
|
20
|
+
end
|
21
|
+
|
22
|
+
def refresh_token
|
23
|
+
payload = {
|
24
|
+
data: refresh_token_data,
|
25
|
+
iss: Rails.application.class.module_parent_name,
|
26
|
+
iat: Time.now.to_i,
|
27
|
+
exp: Time.now.to_i + 14 * 24 * 3600
|
16
28
|
}
|
17
29
|
JWT.encode payload, Rails.application.secrets.secret_key_base, 'HS256' # [1]
|
18
30
|
end
|
@@ -27,7 +39,7 @@ module Credible
|
|
27
39
|
|
28
40
|
private
|
29
41
|
|
30
|
-
def
|
42
|
+
def access_token_data
|
31
43
|
{
|
32
44
|
session_id: id,
|
33
45
|
user_id: user.id,
|
@@ -37,6 +49,12 @@ module Credible
|
|
37
49
|
}
|
38
50
|
}
|
39
51
|
end
|
52
|
+
|
53
|
+
def refresh_token_data
|
54
|
+
{
|
55
|
+
session_id: id
|
56
|
+
}
|
57
|
+
end
|
40
58
|
end
|
41
59
|
end
|
42
60
|
|
data/lib/credible/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: credible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thom Bruce
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|