rodauth-oauth 0.10.4 → 1.0.0.pre.beta2
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/MIGRATION-GUIDE-v1.md +286 -0
- data/README.md +28 -35
- data/doc/release_notes/1_0_0_beta1.md +38 -0
- data/doc/release_notes/1_0_0_beta2.md +34 -0
- data/lib/generators/rodauth/oauth/install_generator.rb +0 -1
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +21 -11
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_search.html.erb +1 -1
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_verification.html.erb +2 -2
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/new_oauth_application.html.erb +1 -6
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application.html.erb +0 -2
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_grants.html.erb +41 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_applications.html.erb +2 -2
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_grants.html.erb +37 -0
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +57 -57
- data/lib/rodauth/features/oauth_application_management.rb +61 -74
- data/lib/rodauth/features/oauth_assertion_base.rb +19 -23
- data/lib/rodauth/features/oauth_authorization_code_grant.rb +62 -90
- data/lib/rodauth/features/oauth_authorize_base.rb +115 -22
- data/lib/rodauth/features/oauth_base.rb +397 -315
- data/lib/rodauth/features/oauth_client_credentials_grant.rb +20 -18
- data/lib/rodauth/features/{oauth_device_grant.rb → oauth_device_code_grant.rb} +62 -73
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +52 -31
- data/lib/rodauth/features/oauth_grant_management.rb +70 -0
- data/lib/rodauth/features/oauth_implicit_grant.rb +29 -27
- data/lib/rodauth/features/oauth_jwt.rb +53 -689
- data/lib/rodauth/features/oauth_jwt_base.rb +458 -0
- data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +48 -17
- data/lib/rodauth/features/oauth_jwt_jwks.rb +47 -0
- data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +116 -0
- data/lib/rodauth/features/oauth_management_base.rb +2 -0
- data/lib/rodauth/features/oauth_pkce.rb +22 -26
- data/lib/rodauth/features/oauth_resource_indicators.rb +33 -25
- data/lib/rodauth/features/oauth_resource_server.rb +59 -0
- data/lib/rodauth/features/oauth_saml_bearer_grant.rb +7 -1
- data/lib/rodauth/features/oauth_token_introspection.rb +76 -46
- data/lib/rodauth/features/oauth_token_revocation.rb +46 -33
- data/lib/rodauth/features/oidc.rb +382 -241
- data/lib/rodauth/features/oidc_dynamic_client_registration.rb +127 -51
- data/lib/rodauth/features/oidc_rp_initiated_logout.rb +115 -0
- data/lib/rodauth/oauth/database_extensions.rb +8 -6
- data/lib/rodauth/oauth/http_extensions.rb +74 -0
- data/lib/rodauth/oauth/railtie.rb +20 -0
- data/lib/rodauth/oauth/ttl_store.rb +2 -0
- data/lib/rodauth/oauth/version.rb +1 -1
- data/lib/rodauth/oauth.rb +29 -1
- data/locales/en.yml +34 -22
- data/locales/pt.yml +34 -22
- data/templates/authorize.str +19 -17
- data/templates/device_search.str +1 -1
- data/templates/device_verification.str +2 -2
- data/templates/jwks_field.str +1 -0
- data/templates/new_oauth_application.str +1 -2
- data/templates/oauth_application.str +2 -2
- data/templates/oauth_application_oauth_grants.str +54 -0
- data/templates/oauth_applications.str +2 -2
- data/templates/oauth_grants.str +52 -0
- metadata +23 -16
- data/lib/generators/rodauth/oauth/templates/app/models/oauth_token.rb +0 -4
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_tokens.html.erb +0 -39
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_tokens.html.erb +0 -35
- data/lib/rodauth/features/oauth.rb +0 -9
- data/lib/rodauth/features/oauth_http_mac.rb +0 -86
- data/lib/rodauth/features/oauth_token_management.rb +0 -81
- data/lib/rodauth/oauth/refinements.rb +0 -48
- data/templates/jwt_public_key_field.str +0 -4
- data/templates/oauth_application_oauth_tokens.str +0 -52
- data/templates/oauth_tokens.str +0 -50
@@ -1,67 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rodauth/oauth"
|
4
|
+
|
3
5
|
module Rodauth
|
4
6
|
Feature.define(:oauth_authorization_code_grant, :OauthAuthorizationCodeGrant) do
|
5
7
|
depends :oauth_authorize_base
|
6
8
|
|
7
|
-
auth_value_method :
|
9
|
+
auth_value_method :oauth_response_mode, "form_post"
|
10
|
+
|
11
|
+
def oauth_grant_types_supported
|
12
|
+
super | %w[authorization_code]
|
13
|
+
end
|
14
|
+
|
15
|
+
def oauth_response_types_supported
|
16
|
+
super | %w[code]
|
17
|
+
end
|
18
|
+
|
19
|
+
def oauth_response_modes_supported
|
20
|
+
super | %w[query form_post]
|
21
|
+
end
|
8
22
|
|
9
23
|
private
|
10
24
|
|
11
25
|
def validate_authorize_params
|
12
26
|
super
|
13
27
|
|
14
|
-
|
28
|
+
response_mode = param_or_nil("response_mode")
|
15
29
|
|
16
|
-
redirect_response_error("invalid_request") if
|
17
|
-
|
18
|
-
try_approval_prompt if use_oauth_access_type? && request.get?
|
30
|
+
redirect_response_error("invalid_request") if response_mode && !oauth_response_modes_supported.include?(response_mode)
|
19
31
|
end
|
20
32
|
|
21
|
-
def
|
33
|
+
def validate_token_params
|
22
34
|
redirect_response_error("invalid_request") if param_or_nil("grant_type") == "authorization_code" && !param_or_nil("code")
|
23
35
|
super
|
24
36
|
end
|
25
37
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
return unless approval_prompt && approval_prompt == "auto"
|
30
|
-
|
31
|
-
return if db[oauth_grants_table].where(
|
32
|
-
oauth_grants_account_id_column => account_id,
|
33
|
-
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
|
34
|
-
oauth_grants_redirect_uri_column => redirect_uri,
|
35
|
-
oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
|
36
|
-
oauth_grants_access_type_column => "online"
|
37
|
-
).count.zero?
|
38
|
-
|
39
|
-
# if there's a previous oauth grant for the params combo, it means that this user has approved before.
|
40
|
-
request.env["REQUEST_METHOD"] = "POST"
|
41
|
-
end
|
38
|
+
def do_authorize(response_params = {}, response_mode = param_or_nil("response_mode"))
|
39
|
+
response_mode ||= oauth_response_mode
|
42
40
|
|
43
|
-
|
44
|
-
# Access Type flow
|
45
|
-
if use_oauth_access_type? && (access_type = param_or_nil("access_type"))
|
46
|
-
create_params[oauth_grants_access_type_column] = access_type
|
47
|
-
end
|
41
|
+
redirect_response_error("invalid_request") unless response_mode.nil? || supported_response_mode?(response_mode)
|
48
42
|
|
49
|
-
|
50
|
-
end
|
43
|
+
response_type = param_or_nil("response_type")
|
51
44
|
|
52
|
-
|
53
|
-
case param("response_type")
|
45
|
+
redirect_response_error("invalid_request") unless response_type.nil? || supported_response_type?(response_type)
|
54
46
|
|
55
|
-
|
56
|
-
|
47
|
+
case response_type
|
48
|
+
when "code", nil
|
57
49
|
response_params.replace(_do_authorize_code)
|
58
|
-
when "none"
|
59
|
-
response_mode ||= "none"
|
60
|
-
when "", nil
|
61
|
-
response_mode ||= oauth_response_mode
|
62
|
-
response_params.replace(_do_authorize_code)
|
63
|
-
else
|
64
|
-
return super if response_params.empty?
|
65
50
|
end
|
66
51
|
|
67
52
|
response_params["state"] = param("state") if param_or_nil("state")
|
@@ -70,11 +55,11 @@ module Rodauth
|
|
70
55
|
end
|
71
56
|
|
72
57
|
def _do_authorize_code
|
73
|
-
create_params = {
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
58
|
+
create_params = {
|
59
|
+
oauth_grants_type_column => "authorization_code",
|
60
|
+
oauth_grants_account_id_column => account_id
|
61
|
+
}
|
62
|
+
|
78
63
|
{ "code" => create_oauth_grant(create_params) }
|
79
64
|
end
|
80
65
|
|
@@ -82,7 +67,7 @@ module Rodauth
|
|
82
67
|
redirect_url = URI.parse(redirect_uri)
|
83
68
|
case mode
|
84
69
|
when "query"
|
85
|
-
params = params.map { |k, v| "#{k}=#{v}" }
|
70
|
+
params = params.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }
|
86
71
|
params << redirect_url.query if redirect_url.query
|
87
72
|
redirect_url.query = params.join("&")
|
88
73
|
redirect(redirect_url.to_s)
|
@@ -94,7 +79,7 @@ module Rodauth
|
|
94
79
|
<form method="post" action="#{redirect_uri}">
|
95
80
|
#{
|
96
81
|
params.map do |name, value|
|
97
|
-
"<input type=\"hidden\" name=\"#{name}\" value=\"#{scope.h(value)}\" />"
|
82
|
+
"<input type=\"hidden\" name=\"#{scope.h(name)}\" value=\"#{scope.h(value)}\" />"
|
98
83
|
end.join
|
99
84
|
}
|
100
85
|
<input type="submit" class="btn btn-outline-primary" value="#{scope.h(oauth_authorize_post_button)}"/>
|
@@ -102,70 +87,57 @@ module Rodauth
|
|
102
87
|
</body>
|
103
88
|
</html>
|
104
89
|
FORM
|
105
|
-
|
106
|
-
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def _redirect_response_error(redirect_url, query_params)
|
94
|
+
response_mode = param_or_nil("response_mode") || oauth_response_mode
|
95
|
+
|
96
|
+
case response_mode
|
97
|
+
when "form_post"
|
98
|
+
response["Content-Type"] = "text/html"
|
99
|
+
response.write <<-FORM
|
100
|
+
<html>
|
101
|
+
<head><title></title></head>
|
102
|
+
<body onload="javascript:document.forms[0].submit()">
|
103
|
+
<form method="post" action="#{redirect_uri}">
|
104
|
+
#{
|
105
|
+
query_params.map do |name, value|
|
106
|
+
"<input type=\"hidden\" name=\"#{name}\" value=\"#{scope.h(value)}\" />"
|
107
|
+
end.join
|
108
|
+
}
|
109
|
+
</form>
|
110
|
+
</body>
|
111
|
+
</html>
|
112
|
+
FORM
|
113
|
+
request.halt
|
107
114
|
else
|
108
115
|
super
|
109
116
|
end
|
110
117
|
end
|
111
118
|
|
112
|
-
def
|
119
|
+
def create_token(grant_type)
|
113
120
|
return super unless supported_grant_type?(grant_type, "authorization_code")
|
114
121
|
|
115
|
-
|
116
|
-
|
122
|
+
grant_params = {
|
123
|
+
oauth_grants_type_column => grant_type,
|
117
124
|
oauth_grants_code_column => param("code"),
|
118
125
|
oauth_grants_redirect_uri_column => param("redirect_uri"),
|
119
|
-
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column]
|
120
|
-
oauth_grants_revoked_at_column => nil
|
121
|
-
).where(Sequel[oauth_grants_expires_in_column] >= Sequel::CURRENT_TIMESTAMP)
|
122
|
-
.for_update
|
123
|
-
.first
|
124
|
-
|
125
|
-
redirect_response_error("invalid_grant") unless oauth_grant
|
126
|
-
|
127
|
-
create_params = {
|
128
|
-
oauth_tokens_account_id_column => oauth_grant[oauth_grants_account_id_column],
|
129
|
-
oauth_tokens_oauth_application_id_column => oauth_grant[oauth_grants_oauth_application_id_column],
|
130
|
-
oauth_tokens_oauth_grant_id_column => oauth_grant[oauth_grants_id_column],
|
131
|
-
oauth_tokens_scopes_column => oauth_grant[oauth_grants_scopes_column]
|
126
|
+
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column]
|
132
127
|
}
|
133
|
-
create_oauth_token_from_authorization_code(oauth_grant, create_params, !use_oauth_access_type?)
|
134
|
-
end
|
135
|
-
|
136
|
-
ACCESS_TYPES = %w[offline online].freeze
|
137
|
-
|
138
|
-
def check_valid_access_type?
|
139
|
-
return true unless use_oauth_access_type?
|
140
128
|
|
141
|
-
|
142
|
-
!access_type || ACCESS_TYPES.include?(access_type)
|
143
|
-
end
|
144
|
-
|
145
|
-
APPROVAL_PROMPTS = %w[force auto].freeze
|
146
|
-
|
147
|
-
def check_valid_approval_prompt?
|
148
|
-
return true unless use_oauth_access_type?
|
149
|
-
|
150
|
-
approval_prompt = param_or_nil("approval_prompt")
|
151
|
-
!approval_prompt || APPROVAL_PROMPTS.include?(approval_prompt)
|
129
|
+
create_token_from_authorization_code(grant_params)
|
152
130
|
end
|
153
131
|
|
154
132
|
def check_valid_response_type?
|
155
133
|
response_type = param_or_nil("response_type")
|
156
134
|
|
157
|
-
response_type
|
135
|
+
response_type == "code" || response_type == "none" || super
|
158
136
|
end
|
159
137
|
|
160
138
|
def oauth_server_metadata_body(*)
|
161
139
|
super.tap do |data|
|
162
140
|
data[:authorization_endpoint] = authorize_url
|
163
|
-
data[:response_types_supported] << "code"
|
164
|
-
|
165
|
-
data[:response_modes_supported] << "query"
|
166
|
-
data[:response_modes_supported] << "form_post"
|
167
|
-
|
168
|
-
data[:grant_types_supported] << "authorization_code"
|
169
141
|
end
|
170
142
|
end
|
171
143
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rodauth/oauth"
|
4
|
+
|
3
5
|
module Rodauth
|
4
6
|
Feature.define(:oauth_authorize_base, :OauthAuthorizeBase) do
|
5
7
|
depends :oauth_base
|
@@ -12,17 +14,22 @@ module Rodauth
|
|
12
14
|
button "Authorize", "oauth_authorize"
|
13
15
|
button "Back to Client Application", "oauth_authorize_post"
|
14
16
|
|
15
|
-
|
17
|
+
auth_value_method :use_oauth_access_type?, false
|
18
|
+
|
19
|
+
auth_value_method :oauth_grants_access_type_column, :access_type
|
20
|
+
|
21
|
+
translatable_method :authorize_page_lead, "The application %<name>s would like to access your data"
|
22
|
+
translatable_method :oauth_grants_scopes_label, "Scopes"
|
16
23
|
translatable_method :oauth_applications_contacts_label, "Contacts"
|
17
24
|
translatable_method :oauth_applications_tos_uri_label, "Terms of service URL"
|
18
25
|
translatable_method :oauth_applications_policy_uri_label, "Policy URL"
|
26
|
+
translatable_method :oauth_unsupported_response_type_message, "Unsupported response type"
|
27
|
+
translatable_method :oauth_authorize_parameter_required, "'%<parameter>s' is a required parameter"
|
19
28
|
|
20
29
|
# /authorize
|
21
|
-
|
22
|
-
next unless is_authorization_server?
|
23
|
-
|
24
|
-
before_authorize_route
|
30
|
+
auth_server_route(:authorize) do |r|
|
25
31
|
require_authorizable_account
|
32
|
+
before_authorize_route
|
26
33
|
|
27
34
|
validate_authorize_params
|
28
35
|
|
@@ -49,14 +56,24 @@ module Rodauth
|
|
49
56
|
end
|
50
57
|
end
|
51
58
|
|
59
|
+
def authorize_scopes
|
60
|
+
scopes || begin
|
61
|
+
oauth_application[oauth_applications_scopes_column].split(oauth_scope_separator)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
52
65
|
private
|
53
66
|
|
54
67
|
def validate_authorize_params
|
55
68
|
redirect_response_error("invalid_request", request.referer || default_redirect) unless oauth_application && check_valid_redirect_uri?
|
56
69
|
|
57
|
-
redirect_response_error("
|
70
|
+
redirect_response_error("unsupported_response_type") unless check_valid_response_type?
|
71
|
+
|
72
|
+
redirect_response_error("invalid_request") unless check_valid_access_type? && check_valid_approval_prompt?
|
58
73
|
|
59
|
-
|
74
|
+
try_approval_prompt if use_oauth_access_type? && request.get?
|
75
|
+
|
76
|
+
redirect_response_error("invalid_scope") if (request.post? || param_or_nil("scope")) && !check_valid_scopes?
|
60
77
|
end
|
61
78
|
|
62
79
|
def check_valid_response_type?
|
@@ -64,12 +81,55 @@ module Rodauth
|
|
64
81
|
end
|
65
82
|
|
66
83
|
def check_valid_redirect_uri?
|
67
|
-
oauth_application[oauth_applications_redirect_uri_column].split(" ")
|
84
|
+
application_redirect_uris = oauth_application[oauth_applications_redirect_uri_column].split(" ")
|
85
|
+
|
86
|
+
if (redirect_uri = param_or_nil("redirect_uri"))
|
87
|
+
application_redirect_uris.include?(redirect_uri)
|
88
|
+
else
|
89
|
+
set_error_flash(oauth_authorize_parameter_required(parameter: "redirect_uri")) if application_redirect_uris.size > 1
|
90
|
+
|
91
|
+
true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
ACCESS_TYPES = %w[offline online].freeze
|
96
|
+
|
97
|
+
def check_valid_access_type?
|
98
|
+
return true unless use_oauth_access_type?
|
99
|
+
|
100
|
+
access_type = param_or_nil("access_type")
|
101
|
+
!access_type || ACCESS_TYPES.include?(access_type)
|
102
|
+
end
|
103
|
+
|
104
|
+
APPROVAL_PROMPTS = %w[force auto].freeze
|
105
|
+
|
106
|
+
def check_valid_approval_prompt?
|
107
|
+
return true unless use_oauth_access_type?
|
108
|
+
|
109
|
+
approval_prompt = param_or_nil("approval_prompt")
|
110
|
+
!approval_prompt || APPROVAL_PROMPTS.include?(approval_prompt)
|
111
|
+
end
|
112
|
+
|
113
|
+
def try_approval_prompt
|
114
|
+
approval_prompt = param_or_nil("approval_prompt")
|
115
|
+
|
116
|
+
return unless approval_prompt && approval_prompt == "auto"
|
117
|
+
|
118
|
+
return if db[oauth_grants_table].where(
|
119
|
+
oauth_grants_account_id_column => account_id,
|
120
|
+
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
|
121
|
+
oauth_grants_redirect_uri_column => redirect_uri,
|
122
|
+
oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
|
123
|
+
oauth_grants_access_type_column => "online"
|
124
|
+
).count.zero?
|
125
|
+
|
126
|
+
# if there's a previous oauth grant for the params combo, it means that this user has approved before.
|
127
|
+
request.env["REQUEST_METHOD"] = "POST"
|
68
128
|
end
|
69
129
|
|
70
130
|
def authorization_required
|
71
131
|
if accepts_json?
|
72
|
-
throw_json_response_error(
|
132
|
+
throw_json_response_error(oauth_authorization_required_error_status, "invalid_client")
|
73
133
|
else
|
74
134
|
set_redirect_error_flash(require_authorization_error_flash)
|
75
135
|
redirect(authorize_path)
|
@@ -80,29 +140,62 @@ module Rodauth
|
|
80
140
|
|
81
141
|
def authorize_response(params, mode); end
|
82
142
|
|
83
|
-
def
|
84
|
-
#
|
85
|
-
|
86
|
-
.update(oauth_grants_revoked_at_column => Sequel::CURRENT_TIMESTAMP)
|
143
|
+
def create_token_from_authorization_code(grant_params, should_generate_refresh_token = !use_oauth_access_type?, oauth_grant: nil)
|
144
|
+
# fetch oauth grant
|
145
|
+
oauth_grant ||= valid_locked_oauth_grant(grant_params)
|
87
146
|
|
88
147
|
should_generate_refresh_token ||= oauth_grant[oauth_grants_access_type_column] == "offline"
|
89
148
|
|
90
|
-
|
149
|
+
generate_token(oauth_grant, should_generate_refresh_token)
|
91
150
|
end
|
92
151
|
|
93
152
|
def create_oauth_grant(create_params = {})
|
94
|
-
create_params
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
)
|
153
|
+
create_params[oauth_grants_oauth_application_id_column] ||= oauth_application[oauth_applications_id_column]
|
154
|
+
create_params[oauth_grants_redirect_uri_column] ||= redirect_uri
|
155
|
+
create_params[oauth_grants_expires_in_column] ||= Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: oauth_grant_expires_in)
|
156
|
+
create_params[oauth_grants_scopes_column] ||= scopes.join(oauth_scope_separator)
|
157
|
+
|
158
|
+
if use_oauth_access_type? && (access_type = param_or_nil("access_type"))
|
159
|
+
create_params[oauth_grants_access_type_column] = access_type
|
160
|
+
end
|
100
161
|
|
101
162
|
ds = db[oauth_grants_table]
|
102
163
|
|
164
|
+
create_params[oauth_grants_code_column] = oauth_unique_id_generator
|
165
|
+
|
166
|
+
if oauth_reuse_access_token
|
167
|
+
unique_conds = Hash[oauth_grants_unique_columns.map { |column| [column, create_params[column]] }]
|
168
|
+
valid_grant = valid_oauth_grant_ds(unique_conds).select(oauth_grants_id_column).first
|
169
|
+
if valid_grant
|
170
|
+
create_params[oauth_grants_id_column] = valid_grant[oauth_grants_id_column]
|
171
|
+
rescue_from_uniqueness_error do
|
172
|
+
__insert_or_update_and_return__(
|
173
|
+
ds,
|
174
|
+
oauth_grants_id_column,
|
175
|
+
[oauth_grants_id_column],
|
176
|
+
create_params
|
177
|
+
)
|
178
|
+
end
|
179
|
+
return create_params[oauth_grants_code_column]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
103
183
|
rescue_from_uniqueness_error do
|
104
|
-
|
105
|
-
|
184
|
+
if __one_oauth_token_per_account
|
185
|
+
__insert_or_update_and_return__(
|
186
|
+
ds,
|
187
|
+
oauth_grants_id_column,
|
188
|
+
oauth_grants_unique_columns,
|
189
|
+
create_params,
|
190
|
+
nil,
|
191
|
+
{
|
192
|
+
oauth_grants_expires_in_column => Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: oauth_grant_expires_in),
|
193
|
+
oauth_grants_revoked_at_column => nil
|
194
|
+
}
|
195
|
+
)
|
196
|
+
else
|
197
|
+
__insert_and_return__(ds, oauth_grants_id_column, create_params)
|
198
|
+
end
|
106
199
|
end
|
107
200
|
create_params[oauth_grants_code_column]
|
108
201
|
end
|