rodauth-oauth 1.3.2 → 1.4.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 +17 -10
- data/doc/release_notes/1_4_0.md +49 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +23 -23
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/frontchannel_logout.html.erb +10 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_applications.html.erb +1 -1
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +20 -0
- data/lib/generators/rodauth/oauth/views_generator.rb +2 -2
- data/lib/rodauth/features/oauth_application_management.rb +1 -1
- data/lib/rodauth/features/oauth_assertion_base.rb +1 -1
- data/lib/rodauth/features/oauth_authorize_base.rb +1 -1
- data/lib/rodauth/features/oauth_base.rb +31 -30
- data/lib/rodauth/features/oauth_device_code_grant.rb +2 -2
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +1 -0
- data/lib/rodauth/features/oauth_grant_management.rb +1 -1
- data/lib/rodauth/features/oauth_jwt.rb +3 -3
- data/lib/rodauth/features/oauth_jwt_base.rb +15 -10
- data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +1 -1
- data/lib/rodauth/features/oauth_jwt_jwks.rb +1 -1
- data/lib/rodauth/features/oauth_resource_server.rb +1 -1
- data/lib/rodauth/features/oauth_saml_bearer_grant.rb +79 -47
- data/lib/rodauth/features/oauth_tls_client_auth.rb +1 -1
- data/lib/rodauth/features/oauth_token_introspection.rb +1 -1
- data/lib/rodauth/features/oauth_token_revocation.rb +1 -1
- data/lib/rodauth/features/oidc.rb +27 -8
- data/lib/rodauth/features/oidc_backchannel_logout.rb +120 -0
- data/lib/rodauth/features/oidc_dynamic_client_registration.rb +25 -0
- data/lib/rodauth/features/oidc_frontchannel_logout.rb +134 -0
- data/lib/rodauth/features/oidc_logout_base.rb +76 -0
- data/lib/rodauth/features/oidc_rp_initiated_logout.rb +29 -6
- data/lib/rodauth/features/oidc_session_management.rb +89 -0
- data/lib/rodauth/oauth/http_extensions.rb +1 -1
- data/lib/rodauth/oauth/version.rb +1 -1
- data/locales/en.yml +9 -0
- data/locales/pt.yml +9 -0
- data/templates/check_session.str +67 -0
- data/templates/frontchannel_logout.str +17 -0
- metadata +11 -2
@@ -4,11 +4,15 @@ require "rodauth/oauth"
|
|
4
4
|
|
5
5
|
module Rodauth
|
6
6
|
Feature.define(:oidc_rp_initiated_logout, :OidcRpInitiatedLogout) do
|
7
|
-
depends :
|
7
|
+
depends :oidc_logout_base
|
8
|
+
response "oidc_logout"
|
8
9
|
|
9
10
|
auth_value_method :oauth_applications_post_logout_redirect_uris_column, :post_logout_redirect_uris
|
11
|
+
translatable_method :oauth_invalid_id_token_hint_message, "Invalid ID token hint"
|
10
12
|
translatable_method :oauth_invalid_post_logout_redirect_uri_message, "Invalid post logout redirect URI"
|
11
13
|
|
14
|
+
attr_reader :oidc_logout_redirect
|
15
|
+
|
12
16
|
# /oidc-logout
|
13
17
|
auth_server_route(:oidc_logout) do |r|
|
14
18
|
require_authorizable_account
|
@@ -19,7 +23,7 @@ module Rodauth
|
|
19
23
|
catch_error do
|
20
24
|
validate_oidc_logout_params
|
21
25
|
|
22
|
-
oauth_application = nil
|
26
|
+
claims = oauth_application = nil
|
23
27
|
|
24
28
|
if (id_token_hint = param_or_nil("id_token_hint"))
|
25
29
|
#
|
@@ -32,7 +36,12 @@ module Rodauth
|
|
32
36
|
#
|
33
37
|
claims = jwt_decode(id_token_hint, verify_claims: false)
|
34
38
|
|
35
|
-
redirect_logout_with_error(
|
39
|
+
redirect_logout_with_error(oauth_invalid_id_token_hint_message) unless claims
|
40
|
+
|
41
|
+
# If the ID Token's sid claim does not correspond to the RP's current session or a
|
42
|
+
# recent session at the OP, the OP SHOULD treat the logout request as suspect, and
|
43
|
+
# MAY decline to act upon it.
|
44
|
+
redirect_logout_with_error(oauth_invalid_client_message) if claims["sid"] && !active_sessions?(claims["sid"])
|
36
45
|
|
37
46
|
oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["aud"]).first
|
38
47
|
oauth_grant = db[oauth_grants_table]
|
@@ -40,9 +49,15 @@ module Rodauth
|
|
40
49
|
.where(oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column])
|
41
50
|
.first
|
42
51
|
|
52
|
+
unique_account_id = if oauth_grant
|
53
|
+
oauth_grant[oauth_grants_account_id_column]
|
54
|
+
else
|
55
|
+
account_id
|
56
|
+
end
|
57
|
+
|
43
58
|
# check whether ID token belongs to currently logged-in user
|
44
|
-
redirect_logout_with_error(oauth_invalid_client_message) unless
|
45
|
-
|
59
|
+
redirect_logout_with_error(oauth_invalid_client_message) unless claims["sub"] == jwt_subject(unique_account_id,
|
60
|
+
oauth_application)
|
46
61
|
|
47
62
|
# When an id_token_hint parameter is present, the OP MUST validate that it was the issuer of the ID Token.
|
48
63
|
redirect_logout_with_error(oauth_invalid_client_message) unless claims && claims["iss"] == oauth_jwt_issuer
|
@@ -59,6 +74,8 @@ module Rodauth
|
|
59
74
|
|
60
75
|
if (post_logout_redirect_uri = param_or_nil("post_logout_redirect_uri"))
|
61
76
|
error_message = catch(:default_logout_redirect) do
|
77
|
+
throw(:default_logout_redirect, oauth_invalid_id_token_hint_message) unless claims
|
78
|
+
|
62
79
|
oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["client_id"]).first
|
63
80
|
|
64
81
|
throw(:default_logout_redirect, oauth_invalid_client_message) unless oauth_application
|
@@ -78,7 +95,9 @@ module Rodauth
|
|
78
95
|
post_logout_redirect_uri = post_logout_redirect_uri.to_s
|
79
96
|
end
|
80
97
|
|
81
|
-
|
98
|
+
@oidc_logout_redirect = post_logout_redirect_uri
|
99
|
+
|
100
|
+
require_response(:_oidc_logout_response)
|
82
101
|
end
|
83
102
|
|
84
103
|
end
|
@@ -90,6 +109,10 @@ module Rodauth
|
|
90
109
|
end
|
91
110
|
end
|
92
111
|
|
112
|
+
def _oidc_logout_response
|
113
|
+
redirect(oidc_logout_redirect)
|
114
|
+
end
|
115
|
+
|
93
116
|
private
|
94
117
|
|
95
118
|
# Logout
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rodauth/oauth"
|
4
|
+
|
5
|
+
module Rodauth
|
6
|
+
Feature.define(:oidc_session_management, :OidcSessionManagement) do
|
7
|
+
depends :oidc
|
8
|
+
|
9
|
+
view "check_session", "Check Session", "check_session"
|
10
|
+
|
11
|
+
auth_value_method :oauth_oidc_user_agent_state_cookie_key, "_rodauth_oauth_user_agent_state"
|
12
|
+
auth_value_method :oauth_oidc_user_agent_state_cookie_options, {}.freeze
|
13
|
+
auth_value_method :oauth_oidc_user_agent_state_cookie_expires_in, 365 * 24 * 60 * 60 # 1 year
|
14
|
+
|
15
|
+
auth_value_method :oauth_oidc_user_agent_state_js, nil
|
16
|
+
|
17
|
+
auth_value_methods(
|
18
|
+
:oauth_oidc_session_management_salt
|
19
|
+
)
|
20
|
+
# /authorize
|
21
|
+
auth_server_route(:check_session) do |r|
|
22
|
+
allow_cors(r)
|
23
|
+
|
24
|
+
r.get do
|
25
|
+
set_title(:check_session_page_title)
|
26
|
+
scope.view(_view_opts("check_session").merge(layout: false))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def clear_session
|
31
|
+
super
|
32
|
+
|
33
|
+
# update user agent state in the process
|
34
|
+
# TODO: dangerous if this gets overidden by the user
|
35
|
+
|
36
|
+
user_agent_state_cookie_opts = Hash[oauth_oidc_user_agent_state_cookie_options]
|
37
|
+
user_agent_state_cookie_opts[:value] = oauth_unique_id_generator
|
38
|
+
user_agent_state_cookie_opts[:expires] = convert_timestamp(Time.now + oauth_oidc_user_agent_state_cookie_expires_in)
|
39
|
+
user_agent_state_cookie_opts[:secure] = true
|
40
|
+
::Rack::Utils.set_cookie_header!(response.headers, oauth_oidc_user_agent_state_cookie_key, user_agent_state_cookie_opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def do_authorize(*)
|
46
|
+
params, mode = super
|
47
|
+
|
48
|
+
params["session_state"] = generate_session_state
|
49
|
+
|
50
|
+
[params, mode]
|
51
|
+
end
|
52
|
+
|
53
|
+
def response_error_params(*)
|
54
|
+
payload = super
|
55
|
+
|
56
|
+
return payload unless request.path == authorize_path
|
57
|
+
|
58
|
+
payload["session_state"] = generate_session_state
|
59
|
+
payload
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate_session_state
|
63
|
+
salt = oauth_oidc_session_management_salt
|
64
|
+
|
65
|
+
uri = URI(redirect_uri)
|
66
|
+
origin = if uri.respond_to?(:origin)
|
67
|
+
uri.origin
|
68
|
+
else
|
69
|
+
# TODO: remove when not supporting uri < 0.11
|
70
|
+
"#{uri.scheme}://#{uri.host}#{":#{uri.port}" if uri.port != uri.default_port}"
|
71
|
+
end
|
72
|
+
session_id = "#{oauth_application[oauth_applications_client_id_column]} " \
|
73
|
+
"#{origin} " \
|
74
|
+
"#{request.cookies[oauth_oidc_user_agent_state_cookie_key]} #{salt}"
|
75
|
+
|
76
|
+
"#{Digest::SHA256.hexdigest(session_id)}.#{salt}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def oauth_server_metadata_body(*)
|
80
|
+
super.tap do |data|
|
81
|
+
data[:check_session_iframe] = check_session_url
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def oauth_oidc_session_management_salt
|
86
|
+
oauth_unique_id_generator
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/locales/en.yml
CHANGED
@@ -8,7 +8,9 @@ en:
|
|
8
8
|
device_verification_notice_flash: "The device is verified"
|
9
9
|
user_code_not_found_error_flash: "No device to authorize with the given user code"
|
10
10
|
authorize_page_title: "Authorize"
|
11
|
+
frontchannel_logout_page_title: "Logout"
|
11
12
|
authorize_page_lead: "The application %{name} would like to access your data."
|
13
|
+
oauth_frontchannel_logout_redirecting_lead: "You are being redirected..."
|
12
14
|
authorize_error_page_title: "Authorize Error"
|
13
15
|
oauth_cancel_button: "Cancel"
|
14
16
|
oauth_applications_page_title: "Oauth Applications"
|
@@ -18,6 +20,7 @@ en:
|
|
18
20
|
oauth_grants_page_title: "My Oauth Grants"
|
19
21
|
device_verification_page_title: "Device Verification"
|
20
22
|
device_search_page_title: "Device Search"
|
23
|
+
check_session_page_title: "Check Session"
|
21
24
|
oauth_management_pagination_previous_button: "Previous"
|
22
25
|
oauth_management_pagination_next_button: "Next"
|
23
26
|
oauth_grants_type_label: "Grant Type"
|
@@ -41,6 +44,8 @@ en:
|
|
41
44
|
oauth_grant_user_code_label: "User code"
|
42
45
|
oauth_grant_user_jws_jwk_label: "JSON Web Keys"
|
43
46
|
oauth_grant_user_jwt_public_key_label: "Public key"
|
47
|
+
oauth_frontchannel_logout_redirecting_label: "please click %{link} if your browser does not redirect you in a few seconds."
|
48
|
+
oauth_frontchannel_logout_redirecting_link_label: "here"
|
44
49
|
oauth_application_button: "Register"
|
45
50
|
oauth_authorize_button: "Authorize"
|
46
51
|
oauth_grant_revoke_button: "Revoke"
|
@@ -68,3 +73,7 @@ en:
|
|
68
73
|
oauth_invalid_scope_message: "The Access Token expired"
|
69
74
|
oauth_authorize_parameter_required: "Invalid or missing '%{parameter}'"
|
70
75
|
oauth_invalid_post_logout_redirect_uri_message: "Invalid post logout redirect URI"
|
76
|
+
oauth_saml_assertion_not_base64_message: "SAML assertion must be in base64 format"
|
77
|
+
oauth_saml_assertion_single_issuer_message: "SAML assertion must have a single issuer"
|
78
|
+
oauth_saml_settings_not_found_message: "No SAML settings found for issuer"
|
79
|
+
oauth_invalid_id_token_hint_message: "Invalid ID token hint"
|
data/locales/pt.yml
CHANGED
@@ -8,7 +8,9 @@ pt:
|
|
8
8
|
device_verification_notice_flash: "O dispositivo foi verificado com sucesso"
|
9
9
|
user_code_not_found_error_flash: "Não existe nenhum dispositivo a ser autorizado com o código de usuário inserido"
|
10
10
|
authorize_page_title: "Autorizar"
|
11
|
+
frontchannel_logout_page_title: "Saindo"
|
11
12
|
authorize_page_lead: "O aplicativo %{name} gostaria de aceder aos seus dados."
|
13
|
+
oauth_frontchannel_logout_redirecting_lead: "Redireccionando.."
|
12
14
|
authorize_error_page_title: Erro de autorização
|
13
15
|
oauth_cancel_button: "Cancelar"
|
14
16
|
oauth_applications_page_title: "Aplicativos OAuth"
|
@@ -18,6 +20,7 @@ pt:
|
|
18
20
|
oauth_grants_page_title: "As minhas concessões Oauth"
|
19
21
|
device_verification_page_title: "Verificação de dispositivo"
|
20
22
|
device_search_page_title: "Pesquisa de dispositivo"
|
23
|
+
check_session_page_title: "Verificação de Sessão"
|
21
24
|
oauth_management_pagination_previous_button: "Anterior"
|
22
25
|
oauth_management_pagination_next_button: "Próxima"
|
23
26
|
oauth_grants_type_label: "Tipo de concessão"
|
@@ -41,6 +44,8 @@ pt:
|
|
41
44
|
oauth_grant_user_code_label: "Código do usuário"
|
42
45
|
oauth_grant_user_jws_jwk_label: "Chaves JSON Web"
|
43
46
|
oauth_grant_user_jwt_public_key_label: "Chave pública"
|
47
|
+
oauth_frontchannel_logout_redirecting_label: "por favor clique %{link} se o seu navegador não lhe redireccionar em alguns segundos."
|
48
|
+
oauth_frontchannel_logout_redirecting_link_label: "aqui"
|
44
49
|
oauth_application_button: "Registar"
|
45
50
|
oauth_authorize_button: "Autorizar"
|
46
51
|
oauth_grant_revoke_button: "Revogar"
|
@@ -68,3 +73,7 @@ pt:
|
|
68
73
|
oauth_invalid_scope_message: "O Token de acesso expirou"
|
69
74
|
oauth_authorize_parameter_required: "'%{parameter}' inválido ou em falta"
|
70
75
|
oauth_invalid_post_logout_redirect_uri_message: "URI de redireccionamento pós-logout inválido"
|
76
|
+
oauth_saml_assertion_not_base64_message: "A asserção SAML tem que estar no formato base64"
|
77
|
+
oauth_saml_assertion_single_issuer_message: "A asserção SAML tem que ter um único emissor"
|
78
|
+
oauth_saml_settings_not_found_message: "Nenhuma configuração SAML encontrada para o emissor"
|
79
|
+
oauth_invalid_id_token_hint_message: "ID token hint inválido"
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
|
+
<title>#{@page_title}</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<script type="text/javascript">
|
10
|
+
window.addEventListener("message", receiveMessage, false);
|
11
|
+
|
12
|
+
function receiveMessage(e) { // e.data has client_id and session_state
|
13
|
+
var client_id = e.data.substr(0, e.data.lastIndexOf(' '));
|
14
|
+
var session_state = e.data.substr(e.data.lastIndexOf(' ') + 1);
|
15
|
+
var salt = session_state.split('.')[1];
|
16
|
+
|
17
|
+
if (!client_id || !session_state || !salt) {
|
18
|
+
postMessage('error', e.origin);
|
19
|
+
return;
|
20
|
+
}
|
21
|
+
|
22
|
+
#{rodauth.oauth_oidc_user_agent_state_js}
|
23
|
+
|
24
|
+
// get_op_user_agent_state() is an OP defined function
|
25
|
+
// that returns the User Agent's login status at the OP.
|
26
|
+
// How it is done is entirely up to the OP.
|
27
|
+
var opuas = getOpUserAgentState();
|
28
|
+
|
29
|
+
// Here, the session_state is calculated in this particular way,
|
30
|
+
// but it is entirely up to the OP how to do it under the
|
31
|
+
// requirements defined in this specification.
|
32
|
+
var msgBuffer = new TextEncoder('utf-8').encode(client_id + ' ' + e.origin + ' ' + opuas + ' ' + salt);
|
33
|
+
crypto.subtle.digest('SHA-256', msgBuffer).then(function(hash) {
|
34
|
+
var hashArray = Array.from(new Uint8Array(hash)); // convert buffer to byte array
|
35
|
+
var hashHex = hashArray
|
36
|
+
.map(function(b) { return b.toString(16).padStart(2, "0"); })
|
37
|
+
.join("");
|
38
|
+
var ss = hashHex + "." + salt;
|
39
|
+
|
40
|
+
var stat = '';
|
41
|
+
if (session_state === ss) {
|
42
|
+
stat = 'unchanged';
|
43
|
+
} else {
|
44
|
+
stat = 'changed';
|
45
|
+
}
|
46
|
+
|
47
|
+
e.source.postMessage(stat, e.origin);
|
48
|
+
});
|
49
|
+
};
|
50
|
+
|
51
|
+
function getOpUserAgentState() {
|
52
|
+
var name = "#{rodauth.oauth_oidc_user_agent_state_cookie_key}=";
|
53
|
+
var ca = document.cookie.split(';');
|
54
|
+
var value = null;
|
55
|
+
for (var i = 0; i < ca.length; i++) {
|
56
|
+
var c = ca[i].trim();
|
57
|
+
if ((c.indexOf(name)) == 0) {
|
58
|
+
value = c.substr(name.length);
|
59
|
+
break;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
return value;
|
64
|
+
}
|
65
|
+
</script>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<div class="mb-3">
|
2
|
+
<h1>#{rodauth.oauth_frontchannel_logout_redirecting_lead}</h1>
|
3
|
+
<p>
|
4
|
+
#{
|
5
|
+
rodauth.oauth_frontchannel_logout_redirecting_label(
|
6
|
+
link: "<a href=\"#{rodauth.frontchannel_logout_redirect}\">" \
|
7
|
+
"#{rodauth.oauth_frontchannel_logout_redirecting_link_label}</a>"
|
8
|
+
)
|
9
|
+
}
|
10
|
+
</p>
|
11
|
+
#{
|
12
|
+
rodauth.frontchannel_logout_urls.map do |logout_url|
|
13
|
+
"<iframe src=\"#{logout_url}\"></iframe>"
|
14
|
+
end.join
|
15
|
+
}
|
16
|
+
</div>
|
17
|
+
<meta http-equiv="refresh" content="#{rodauth.frontchannel_logout_redirect_timeout}; URL=#{rodauth.frontchannel_logout_redirect}" />
|
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: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rodauth
|
@@ -72,6 +72,7 @@ extra_rdoc_files:
|
|
72
72
|
- doc/release_notes/1_3_0.md
|
73
73
|
- doc/release_notes/1_3_1.md
|
74
74
|
- doc/release_notes/1_3_2.md
|
75
|
+
- doc/release_notes/1_4_0.md
|
75
76
|
files:
|
76
77
|
- CHANGELOG.md
|
77
78
|
- LICENSE.txt
|
@@ -115,6 +116,7 @@ files:
|
|
115
116
|
- doc/release_notes/1_3_0.md
|
116
117
|
- doc/release_notes/1_3_1.md
|
117
118
|
- doc/release_notes/1_3_2.md
|
119
|
+
- doc/release_notes/1_4_0.md
|
118
120
|
- lib/generators/rodauth/oauth/install_generator.rb
|
119
121
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_application.rb
|
120
122
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_grant.rb
|
@@ -122,6 +124,7 @@ files:
|
|
122
124
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize_error.erb
|
123
125
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/device_search.html.erb
|
124
126
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/device_verification.html.erb
|
127
|
+
- lib/generators/rodauth/oauth/templates/app/views/rodauth/frontchannel_logout.html.erb
|
125
128
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/new_oauth_application.html.erb
|
126
129
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application.html.erb
|
127
130
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_grants.html.erb
|
@@ -155,9 +158,13 @@ files:
|
|
155
158
|
- lib/rodauth/features/oauth_token_introspection.rb
|
156
159
|
- lib/rodauth/features/oauth_token_revocation.rb
|
157
160
|
- lib/rodauth/features/oidc.rb
|
161
|
+
- lib/rodauth/features/oidc_backchannel_logout.rb
|
158
162
|
- lib/rodauth/features/oidc_dynamic_client_registration.rb
|
163
|
+
- lib/rodauth/features/oidc_frontchannel_logout.rb
|
164
|
+
- lib/rodauth/features/oidc_logout_base.rb
|
159
165
|
- lib/rodauth/features/oidc_rp_initiated_logout.rb
|
160
166
|
- lib/rodauth/features/oidc_self_issued.rb
|
167
|
+
- lib/rodauth/features/oidc_session_management.rb
|
161
168
|
- lib/rodauth/oauth.rb
|
162
169
|
- lib/rodauth/oauth/database_extensions.rb
|
163
170
|
- lib/rodauth/oauth/http_extensions.rb
|
@@ -169,10 +176,12 @@ files:
|
|
169
176
|
- locales/pt.yml
|
170
177
|
- templates/authorize.str
|
171
178
|
- templates/authorize_error.str
|
179
|
+
- templates/check_session.str
|
172
180
|
- templates/client_secret_field.str
|
173
181
|
- templates/description_field.str
|
174
182
|
- templates/device_search.str
|
175
183
|
- templates/device_verification.str
|
184
|
+
- templates/frontchannel_logout.str
|
176
185
|
- templates/homepage_url_field.str
|
177
186
|
- templates/jwks_field.str
|
178
187
|
- templates/name_field.str
|