diff --git a/.env.example.complete b/.env.example.complete index 96a3b448f..e89dc5515 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -274,6 +274,10 @@ OIDC_GROUPS_CLAIM=groups OIDC_REMOVE_FROM_GROUPS=false OIDC_EXTERNAL_ID_CLAIM=sub +# OIDC Logout Feature: Its value should be value of end_session_endpoint from /.well-known/openid-configuration +OIDC_END_SESSION_ENDPOINT=null + + # Disable default third-party services such as Gravatar and Draw.IO # Service-specific options will override this option DISABLE_EXTERNAL_SERVICES=false diff --git a/app/Access/Controllers/OidcController.php b/app/Access/Controllers/OidcController.php index e8c944934..083e83e35 100644 --- a/app/Access/Controllers/OidcController.php +++ b/app/Access/Controllers/OidcController.php @@ -63,4 +63,18 @@ class OidcController extends Controller return redirect()->intended(); } + + /** + * OIDC Logout Feature: Start the authorization logout flow via OIDC. + */ + public function logout() + { + try { + return $this->oidcService->logout(); + } catch (OidcException $exception) { + $this->showErrorNotification($exception->getMessage()); + return redirect('/logout'); + } + } + } diff --git a/app/Access/Oidc/OidcService.php b/app/Access/Oidc/OidcService.php index 6d13fe8f1..bd4964c57 100644 --- a/app/Access/Oidc/OidcService.php +++ b/app/Access/Oidc/OidcService.php @@ -216,6 +216,12 @@ class OidcService $settings->keys, ); + // OIDC Logout Feature: Temporarily save token in session + $access_token_for_logout = $idTokenText; + session()->put("oidctoken", $access_token_for_logout); + + + $returnClaims = Theme::dispatch(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $idToken->getAllClaims(), [ 'access_token' => $accessToken->getToken(), 'expires_in' => $accessToken->getExpires(), @@ -283,4 +289,37 @@ class OidcService { return $this->config()['user_to_groups'] !== false; } + + + /** + * OIDC Logout Feature: Initiate a logout flow. + * + * @throws OidcException + * + * @return string + */ + public function logout() { + + $config = $this->config(); + $app_url = env('APP_URL', null); + $end_session_endpoint = $config["end_session_endpoint"]; + + $oidctoken = session()->get("oidctoken"); + session()->invalidate(); + + if (str_contains($app_url, 'https://')) { + $protocol = 'https://'; + } else { + $protocol = 'http://'; + } + + + + return redirect($end_session_endpoint.'?id_token_hint='.$oidctoken."&post_logout_redirect_uri=".$protocol.$_SERVER['HTTP_HOST']."/"); + + + } + + + } diff --git a/app/Config/oidc.php b/app/Config/oidc.php index 1f73fb688..a624e034c 100644 --- a/app/Config/oidc.php +++ b/app/Config/oidc.php @@ -47,4 +47,9 @@ return [ 'groups_claim' => env('OIDC_GROUPS_CLAIM', 'groups'), // When syncing groups, remove any groups that no longer match. Otherwise sync only adds new groups. 'remove_from_groups' => env('OIDC_REMOVE_FROM_GROUPS', false), + + // OIDC Logout Feature: OAuth2 end_session_endpoint + 'end_session_endpoint' => env('OIDC_END_SESSION_ENDPOINT', null), + ]; + diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php index 97a411d84..8c05dc7ce 100644 --- a/resources/views/common/header.blade.php +++ b/resources/views/common/header.blade.php @@ -93,8 +93,22 @@
  • + +
    + + {{ csrf_field() }}