rodauth-oauth 0.9.2 → 0.9.3
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 +2 -1
- data/doc/release_notes/0_9_3.md +9 -0
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +1 -0
- data/lib/rodauth/features/oauth_base.rb +42 -53
- data/lib/rodauth/features/oauth_jwt.rb +18 -32
- data/lib/rodauth/features/oidc.rb +3 -3
- data/lib/rodauth/oauth/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79fa7abfcf7ea1c0a2594f92bfd7a59e53769dec5a7221a22f740b37471e6e07
|
4
|
+
data.tar.gz: 9f7e8ce4370d44d985940d46d569e3192c35e53cb6e3841094517e64258b2b1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 520a85416c418f93615a471133201c7ec6dd5c16ff9d697a6ca87b609084b58c7b9799c5d3c7a8d02a4fc68ca9750c9ef41dd07dde17c1e1153f0cec8e58f3c1
|
7
|
+
data.tar.gz: 8e7ebc28ba158f43b5226a2de98fc76de8c81e8a8c87dbaa95a69050eed96793e487666389b60be6694437c298fdf23f183a1df098983eeec5f5549df0321c7c
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Rodauth::Oauth
|
2
2
|
|
3
|
-
[](http://rubygems.org/gems/rodauth-oauth)
|
4
|
+
[](https://gitlab.com/honeyryderchuck/rodauth-oauth/pipelines?page=1&scope=all&ref=master)
|
4
5
|
[](https://honeyryderchuck.gitlab.io/rodauth-oauth/coverage/#_AllFiles)
|
5
6
|
|
6
7
|
This is an extension to the `rodauth` gem which implements the [OAuth 2.0 framework](https://tools.ietf.org/html/rfc6749) for an authorization server.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
### 0.9.2 (30/05/2022)
|
2
|
+
|
3
|
+
#### Bugfixes
|
4
|
+
|
5
|
+
* `oauth_jwt`: new access tokens generated via the `"refresh_token"` grant type are now JWT (it was falling back to non JWT behaviour);
|
6
|
+
* `oidc`: a new `id_token` is now generated via the `"refresh_token"` grant type with "rotation" policy (it was being omitted from the response);
|
7
|
+
* `oidc`: fixing calculation of `"auth_time"` claim, which (as per RFC) needs to stay the same across first authentication and subsequent `"refresh_token"` requests;
|
8
|
+
* it requires a new db column (default: `"auth_time"`, datetime) in the `"oauth_tokens"` database;
|
9
|
+
* hash-column `"refresh_token"` will now expose the refresh token (instead of the hash column version) in the `"refresh_token"` grant type response payload (only happened in "non-rotation" refresh token mode).
|
@@ -426,32 +426,40 @@ module Rodauth
|
|
426
426
|
}.merge(params)
|
427
427
|
|
428
428
|
rescue_from_uniqueness_error do
|
429
|
-
|
429
|
+
access_token = _generate_access_token(create_params)
|
430
|
+
refresh_token = _generate_refresh_token(create_params) if should_generate_refresh_token
|
431
|
+
oauth_token = _store_oauth_token(create_params)
|
432
|
+
oauth_token[oauth_tokens_token_column] = access_token
|
433
|
+
oauth_token[oauth_tokens_refresh_token_column] = refresh_token if refresh_token
|
434
|
+
oauth_token
|
435
|
+
end
|
436
|
+
end
|
430
437
|
|
431
|
-
|
432
|
-
|
433
|
-
else
|
434
|
-
create_params[oauth_tokens_token_column] = token
|
435
|
-
end
|
438
|
+
def _generate_access_token(params = {})
|
439
|
+
token = oauth_unique_id_generator
|
436
440
|
|
437
|
-
|
438
|
-
|
439
|
-
|
441
|
+
if oauth_tokens_token_hash_column
|
442
|
+
params[oauth_tokens_token_hash_column] = generate_token_hash(token)
|
443
|
+
else
|
444
|
+
params[oauth_tokens_token_column] = token
|
445
|
+
end
|
440
446
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
447
|
+
token
|
448
|
+
end
|
449
|
+
|
450
|
+
def _generate_refresh_token(params)
|
451
|
+
token = oauth_unique_id_generator
|
452
|
+
|
453
|
+
if oauth_tokens_refresh_token_hash_column
|
454
|
+
params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(token)
|
455
|
+
else
|
456
|
+
params[oauth_tokens_refresh_token_column] = token
|
451
457
|
end
|
458
|
+
|
459
|
+
token
|
452
460
|
end
|
453
461
|
|
454
|
-
def
|
462
|
+
def _store_oauth_token(params = {})
|
455
463
|
ds = db[oauth_tokens_table]
|
456
464
|
|
457
465
|
if __one_oauth_token_per_account
|
@@ -577,43 +585,24 @@ module Rodauth
|
|
577
585
|
|
578
586
|
rescue_from_uniqueness_error do
|
579
587
|
oauth_tokens_ds = db[oauth_tokens_table]
|
580
|
-
|
588
|
+
access_token = _generate_access_token(update_params)
|
581
589
|
|
582
|
-
if
|
583
|
-
update_params
|
590
|
+
if oauth_refresh_token_protection_policy == "rotation"
|
591
|
+
update_params = {
|
592
|
+
**update_params,
|
593
|
+
oauth_tokens_oauth_token_id_column => oauth_token[oauth_tokens_id_column],
|
594
|
+
oauth_tokens_account_id_column => oauth_token[oauth_tokens_account_id_column],
|
595
|
+
oauth_tokens_scopes_column => oauth_token[oauth_tokens_scopes_column]
|
596
|
+
}
|
597
|
+
|
598
|
+
refresh_token = _generate_refresh_token(update_params)
|
584
599
|
else
|
585
|
-
|
600
|
+
refresh_token = param("refresh_token")
|
586
601
|
end
|
602
|
+
oauth_token = __update_and_return__(oauth_tokens_ds, update_params)
|
587
603
|
|
588
|
-
oauth_token =
|
589
|
-
|
590
|
-
**update_params,
|
591
|
-
oauth_tokens_oauth_token_id_column => oauth_token[oauth_tokens_id_column],
|
592
|
-
oauth_tokens_scopes_column => oauth_token[oauth_tokens_scopes_column]
|
593
|
-
}
|
594
|
-
|
595
|
-
refresh_token = oauth_unique_id_generator
|
596
|
-
|
597
|
-
if oauth_tokens_refresh_token_hash_column
|
598
|
-
insert_params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(refresh_token)
|
599
|
-
else
|
600
|
-
insert_params[oauth_tokens_refresh_token_column] = refresh_token
|
601
|
-
end
|
602
|
-
|
603
|
-
# revoke the refresh token
|
604
|
-
oauth_tokens_ds.where(oauth_tokens_id_column => oauth_token[oauth_tokens_id_column])
|
605
|
-
.update(oauth_tokens_revoked_at_column => Sequel::CURRENT_TIMESTAMP)
|
606
|
-
|
607
|
-
insert_params[oauth_tokens_oauth_token_id_column] = oauth_token[oauth_tokens_id_column]
|
608
|
-
__insert_and_return__(oauth_tokens_ds, oauth_tokens_id_column, insert_params)
|
609
|
-
else
|
610
|
-
# includes none
|
611
|
-
ds = oauth_tokens_ds.where(oauth_tokens_id_column => oauth_token[oauth_tokens_id_column])
|
612
|
-
__update_and_return__(ds, update_params)
|
613
|
-
end
|
614
|
-
|
615
|
-
oauth_token[oauth_tokens_token_column] = token
|
616
|
-
oauth_token[oauth_tokens_refresh_token_column] = refresh_token if refresh_token
|
604
|
+
oauth_token[oauth_tokens_token_column] = access_token
|
605
|
+
oauth_token[oauth_tokens_refresh_token_column] = refresh_token
|
617
606
|
oauth_token
|
618
607
|
end
|
619
608
|
end
|
@@ -66,7 +66,6 @@ module Rodauth
|
|
66
66
|
:jwt_encode,
|
67
67
|
:jwt_decode,
|
68
68
|
:jwks_set,
|
69
|
-
:last_account_login_at,
|
70
69
|
:generate_jti
|
71
70
|
)
|
72
71
|
|
@@ -99,12 +98,6 @@ module Rodauth
|
|
99
98
|
|
100
99
|
private
|
101
100
|
|
102
|
-
unless method_defined?(:last_account_login_at)
|
103
|
-
def last_account_login_at
|
104
|
-
nil
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
101
|
def issuer
|
109
102
|
@issuer ||= oauth_jwt_token_issuer || authorization_server_url
|
110
103
|
end
|
@@ -175,41 +168,38 @@ module Rodauth
|
|
175
168
|
|
176
169
|
# /token
|
177
170
|
|
178
|
-
def
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
if should_generate_refresh_token
|
185
|
-
refresh_token = oauth_unique_id_generator
|
186
|
-
|
187
|
-
if oauth_tokens_refresh_token_hash_column
|
188
|
-
create_params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(refresh_token)
|
189
|
-
else
|
190
|
-
create_params[oauth_tokens_refresh_token_column] = refresh_token
|
191
|
-
end
|
192
|
-
end
|
171
|
+
def create_oauth_token_from_token(oauth_token, update_params)
|
172
|
+
otoken = super
|
173
|
+
access_token = _generate_jwt_access_token(otoken)
|
174
|
+
otoken[oauth_tokens_token_column] = access_token
|
175
|
+
otoken
|
176
|
+
end
|
193
177
|
|
194
|
-
|
195
|
-
|
178
|
+
def generate_oauth_token(params = {}, should_generate_refresh_token = true)
|
179
|
+
oauth_token = super
|
180
|
+
access_token = _generate_jwt_access_token(oauth_token)
|
181
|
+
oauth_token[oauth_tokens_token_column] = access_token
|
182
|
+
oauth_token
|
183
|
+
end
|
196
184
|
|
185
|
+
def _generate_jwt_access_token(oauth_token)
|
197
186
|
claims = jwt_claims(oauth_token)
|
198
187
|
|
199
188
|
# one of the points of using jwt is avoiding database lookups, so we put here all relevant
|
200
189
|
# token data.
|
201
190
|
claims[:scope] = oauth_token[oauth_tokens_scopes_column]
|
202
191
|
|
203
|
-
|
192
|
+
jwt_encode(claims)
|
193
|
+
end
|
204
194
|
|
205
|
-
|
206
|
-
|
195
|
+
def _generate_access_token(*)
|
196
|
+
# no op
|
207
197
|
end
|
208
198
|
|
209
199
|
def jwt_claims(oauth_token)
|
210
200
|
issued_at = Time.now.to_i
|
211
201
|
|
212
|
-
|
202
|
+
{
|
213
203
|
iss: issuer, # issuer
|
214
204
|
iat: issued_at, # issued at
|
215
205
|
#
|
@@ -227,10 +217,6 @@ module Rodauth
|
|
227
217
|
exp: issued_at + oauth_token_expires_in,
|
228
218
|
aud: (oauth_jwt_audience || oauth_application[oauth_applications_client_id_column])
|
229
219
|
}
|
230
|
-
|
231
|
-
claims[:auth_time] = last_account_login_at.to_i if last_account_login_at
|
232
|
-
|
233
|
-
claims
|
234
220
|
end
|
235
221
|
|
236
222
|
def jwt_subject(oauth_token)
|
@@ -74,6 +74,7 @@ module Rodauth
|
|
74
74
|
|
75
75
|
auth_value_method :oauth_grants_nonce_column, :nonce
|
76
76
|
auth_value_method :oauth_tokens_nonce_column, :nonce
|
77
|
+
auth_value_method :oauth_tokens_auth_time_column, :auth_time
|
77
78
|
|
78
79
|
translatable_method :invalid_scope_message, "The Access Token expired"
|
79
80
|
|
@@ -341,8 +342,7 @@ module Rodauth
|
|
341
342
|
|
342
343
|
# Time when the End-User authentication occurred.
|
343
344
|
#
|
344
|
-
|
345
|
-
id_token_claims[:auth_time] = id_token_claims[:iat]
|
345
|
+
id_token_claims[:auth_time] = oauth_token[oauth_tokens_auth_time_column].to_i
|
346
346
|
|
347
347
|
account = db[accounts_table].where(account_id_column => oauth_token[oauth_tokens_account_id_column]).first
|
348
348
|
|
@@ -488,7 +488,7 @@ module Rodauth
|
|
488
488
|
end
|
489
489
|
end
|
490
490
|
|
491
|
-
scope_claims.unshift("auth_time")
|
491
|
+
scope_claims.unshift("auth_time")
|
492
492
|
|
493
493
|
response_types_supported = metadata[:response_types_supported]
|
494
494
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rodauth-oauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-05-
|
11
|
+
date: 2022-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rodauth
|
@@ -59,6 +59,7 @@ extra_rdoc_files:
|
|
59
59
|
- doc/release_notes/0_9_0.md
|
60
60
|
- doc/release_notes/0_9_1.md
|
61
61
|
- doc/release_notes/0_9_2.md
|
62
|
+
- doc/release_notes/0_9_3.md
|
62
63
|
files:
|
63
64
|
- CHANGELOG.md
|
64
65
|
- LICENSE.txt
|
@@ -89,6 +90,7 @@ files:
|
|
89
90
|
- doc/release_notes/0_9_0.md
|
90
91
|
- doc/release_notes/0_9_1.md
|
91
92
|
- doc/release_notes/0_9_2.md
|
93
|
+
- doc/release_notes/0_9_3.md
|
92
94
|
- lib/generators/rodauth/oauth/install_generator.rb
|
93
95
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_application.rb
|
94
96
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_grant.rb
|