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 <issuer>/.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
namespace BookStack\Access\Controllers;
use BookStack\Access\LoginService;
-use BookStack\Access\SocialAuthService;
+use BookStack\Access\SocialDriverManager;
use BookStack\Exceptions\LoginAttemptEmailNeededException;
use BookStack\Exceptions\LoginAttemptException;
use BookStack\Facades\Activity;
{
use ThrottlesLogins;
- protected SocialAuthService $socialAuthService;
+ protected SocialDriverManager $socialDriverManager;
protected LoginService $loginService;
/**
* Create a new controller instance.
*/
- public function __construct(SocialAuthService $socialAuthService, LoginService $loginService)
+ public function __construct(SocialDriverManager $driverManager, LoginService $loginService)
{
$this->middleware('guest', ['only' => ['getLogin', 'login']]);
$this->middleware('guard:standard,ldap', ['only' => ['login']]);
$this->middleware('guard:standard,ldap,oidc', ['only' => ['logout']]);
- $this->socialAuthService = $socialAuthService;
+ $this->socialDriverManager = $driverManager;
$this->loginService = $loginService;
}
*/
public function getLogin(Request $request)
{
- $socialDrivers = $this->socialAuthService->getActiveDrivers();
+ $socialDrivers = $this->socialDriverManager->getActive();
$authMethod = config('auth.method');
$preventInitiation = $request->get('prevent_auto_init') === 'true';
/**
* Logout user and perform subsequent redirect.
*/
- public function logout(Request $request)
+ public function logout()
{
- Auth::guard()->logout();
- $request->session()->invalidate();
- $request->session()->regenerateToken();
-
- $redirectUri = $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/';
-
- return redirect($redirectUri);
+ return redirect($this->loginService->logout());
}
/**
redirect()->setIntendedUrl($previous);
}
-
- /**
- * Check if login auto-initiate should be valid based upon authentication config.
- */
- protected function shouldAutoInitiate(): bool
- {
- $socialDrivers = $this->socialAuthService->getActiveDrivers();
- $authMethod = config('auth.method');
- $autoRedirect = config('auth.auto_initiate');
-
- return $autoRedirect && count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']);
- }
}
{
protected OidcService $oidcService;
- /**
- * OpenIdController constructor.
- */
public function __construct(OidcService $oidcService)
{
$this->oidcService = $oidcService;
}
/**
- * OIDC Logout Feature: Start the authorization logout flow via OIDC.
+ * Log the user out then start the OIDC RP-initiated logout process.
*/
public function logout()
{
- try {
- return $this->oidcService->logout();
- } catch (OidcException $exception) {
- $this->showErrorNotification($exception->getMessage());
- return redirect('/logout');
- }
+ return redirect($this->oidcService->logout());
}
-
}
use BookStack\Access\LoginService;
use BookStack\Access\RegistrationService;
-use BookStack\Access\SocialAuthService;
+use BookStack\Access\SocialDriverManager;
use BookStack\Exceptions\StoppedAuthenticationException;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Http\Controller;
class RegisterController extends Controller
{
- protected SocialAuthService $socialAuthService;
+ protected SocialDriverManager $socialDriverManager;
protected RegistrationService $registrationService;
protected LoginService $loginService;
* Create a new controller instance.
*/
public function __construct(
- SocialAuthService $socialAuthService,
+ SocialDriverManager $socialDriverManager,
RegistrationService $registrationService,
LoginService $loginService
) {
$this->middleware('guest');
$this->middleware('guard:standard');
- $this->socialAuthService = $socialAuthService;
+ $this->socialDriverManager = $socialDriverManager;
$this->registrationService = $registrationService;
$this->loginService = $loginService;
}
public function getRegister()
{
$this->registrationService->ensureRegistrationAllowed();
- $socialDrivers = $this->socialAuthService->getActiveDrivers();
+ $socialDrivers = $this->socialDriverManager->getActive();
return view('auth.register', [
'socialDrivers' => $socialDrivers,
try {
return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
} catch (SocialSignInAccountNotUsed $exception) {
- if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
+ if ($this->socialAuthService->drivers()->isAutoRegisterEnabled($socialDriver)) {
return $this->socialRegisterCallback($socialDriver, $socialUser);
}
{
$socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
$socialAccount = $this->socialAuthService->newSocialAccount($socialDriver, $socialUser);
- $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
+ $emailVerified = $this->socialAuthService->drivers()->isAutoConfirmEmailEnabled($socialDriver);
// Create an array of the user data to create a new user instance
$userData = [
{
protected const LAST_LOGIN_ATTEMPTED_SESSION_KEY = 'auth-login-last-attempted';
- protected $mfaSession;
- protected $emailConfirmationService;
-
- public function __construct(MfaSession $mfaSession, EmailConfirmationService $emailConfirmationService)
- {
- $this->mfaSession = $mfaSession;
- $this->emailConfirmationService = $emailConfirmationService;
+ public function __construct(
+ protected MfaSession $mfaSession,
+ protected EmailConfirmationService $emailConfirmationService,
+ protected SocialDriverManager $socialDriverManager,
+ ) {
}
/**
return $result;
}
+
+ /**
+ * Logs the current user out of the application.
+ * Returns an app post-redirect path.
+ */
+ public function logout(): string
+ {
+ auth()->logout();
+ session()->invalidate();
+ session()->regenerateToken();
+
+ return $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/';
+ }
+
+ /**
+ * Check if login auto-initiate should be valid based upon authentication config.
+ */
+ protected function shouldAutoInitiate(): bool
+ {
+ $socialDrivers = $this->socialDriverManager->getActive();
+ $authMethod = config('auth.method');
+ $autoRedirect = config('auth.auto_initiate');
+
+ return $autoRedirect && count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']);
+ }
}
$settings->keys,
);
- // OIDC Logout Feature: Temporarily save token in session
- $access_token_for_logout = $idTokenText;
- session()->put("oidctoken", $access_token_for_logout);
-
-
+ session()->put("oidc_id_token", $idTokenText);
$returnClaims = Theme::dispatch(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $idToken->getAllClaims(), [
'access_token' => $accessToken->getToken(),
return $this->config()['user_to_groups'] !== false;
}
-
/**
- * OIDC Logout Feature: Initiate a logout flow.
- *
- * @throws OidcException
- *
- * @return string
+ * Start the RP-initiated logout flow if active, otherwise start a standard logout flow.
+ * Returns a post-app-logout redirect URL.
+ * Reference: https://openid.net/specs/openid-connect-rpinitiated-1_0.html
*/
- public function logout() {
-
- $config = $this->config();
- $app_url = env('APP_URL', '');
- $end_session_endpoint = $config["end_session_endpoint"];
-
- $oidctoken = session()->get("oidctoken");
- session()->invalidate();
-
- if (str_contains($app_url, 'https://')) {
- $protocol = 'https://';
- } else {
- $protocol = 'http://';
- }
-
-
+ public function logout(): string
+ {
+ $endSessionEndpoint = $this->config()["end_session_endpoint"];
- return redirect($end_session_endpoint.'?id_token_hint='.$oidctoken."&post_logout_redirect_uri=".$protocol.$_SERVER['HTTP_HOST']."/");
+ // TODO - Add autodiscovery and false/null config value support.
+ $oidcToken = session()->pull("oidc_id_token");
+ $defaultLogoutUrl = url($this->loginService->logout());
+ $endpointParams = [
+ 'id_token_hint' => $oidcToken,
+ 'post_logout_redirect_uri' => $defaultLogoutUrl,
+ ];
+ return $endSessionEndpoint . '?' . http_build_query($endpointParams);
}
-
-
-
}
throw $error;
}
- $this->actionLogout();
- $url = '/';
+ $url = $this->loginService->logout();
$id = null;
}
);
}
- $this->actionLogout();
+ $this->loginService->logout();
return $redirect;
}
- /**
- * Do the required actions to log a user out.
- */
- protected function actionLogout()
- {
- auth()->logout();
- session()->invalidate();
- }
-
/**
* Get the metadata for this service provider.
*
namespace BookStack\Access;
-use BookStack\Auth\Access\handler;
use BookStack\Exceptions\SocialDriverNotConfigured;
use BookStack\Exceptions\SocialSignInAccountNotUsed;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Users\Models\User;
-use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Laravel\Socialite\Contracts\Factory as Socialite;
use Laravel\Socialite\Contracts\Provider;
use Laravel\Socialite\Contracts\User as SocialUser;
use Laravel\Socialite\Two\GoogleProvider;
-use SocialiteProviders\Manager\SocialiteWasCalled;
use Symfony\Component\HttpFoundation\RedirectResponse;
class SocialAuthService
{
- /**
- * The core socialite library used.
- *
- * @var Socialite
- */
- protected $socialite;
-
- /**
- * @var LoginService
- */
- protected $loginService;
-
- /**
- * The default built-in social drivers we support.
- *
- * @var string[]
- */
- protected $validSocialDrivers = [
- 'google',
- 'github',
- 'facebook',
- 'slack',
- 'twitter',
- 'azure',
- 'okta',
- 'gitlab',
- 'twitch',
- 'discord',
- ];
-
- /**
- * Callbacks to run when configuring a social driver
- * for an initial redirect action.
- * Array is keyed by social driver name.
- * Callbacks are passed an instance of the driver.
- *
- * @var array<string, callable>
- */
- protected $configureForRedirectCallbacks = [];
-
- /**
- * SocialAuthService constructor.
- */
- public function __construct(Socialite $socialite, LoginService $loginService)
- {
- $this->socialite = $socialite;
- $this->loginService = $loginService;
+ public function __construct(
+ protected Socialite $socialite,
+ protected LoginService $loginService,
+ protected SocialDriverManager $driverManager,
+ ) {
}
/**
*/
public function startLogIn(string $socialDriver): RedirectResponse
{
- $driver = $this->validateDriver($socialDriver);
+ $socialDriver = trim(strtolower($socialDriver));
+ $this->driverManager->ensureDriverActive($socialDriver);
- return $this->getDriverForRedirect($driver)->redirect();
+ return $this->getDriverForRedirect($socialDriver)->redirect();
}
/**
*/
public function startRegister(string $socialDriver): RedirectResponse
{
- $driver = $this->validateDriver($socialDriver);
+ $socialDriver = trim(strtolower($socialDriver));
+ $this->driverManager->ensureDriverActive($socialDriver);
- return $this->getDriverForRedirect($driver)->redirect();
+ return $this->getDriverForRedirect($socialDriver)->redirect();
}
/**
*/
public function getSocialUser(string $socialDriver): SocialUser
{
- $driver = $this->validateDriver($socialDriver);
+ $socialDriver = trim(strtolower($socialDriver));
+ $this->driverManager->ensureDriverActive($socialDriver);
- return $this->socialite->driver($driver)->user();
+ return $this->socialite->driver($socialDriver)->user();
}
/**
*/
public function handleLoginCallback(string $socialDriver, SocialUser $socialUser)
{
+ $socialDriver = trim(strtolower($socialDriver));
$socialId = $socialUser->getId();
// Get any attached social accounts or users
}
/**
- * Ensure the social driver is correct and supported.
- *
- * @throws SocialDriverNotConfigured
+ * Get the social driver manager used by this service.
*/
- protected function validateDriver(string $socialDriver): string
+ public function drivers(): SocialDriverManager
{
- $driver = trim(strtolower($socialDriver));
-
- if (!in_array($driver, $this->validSocialDrivers)) {
- abort(404, trans('errors.social_driver_not_found'));
- }
-
- if (!$this->checkDriverConfigured($driver)) {
- throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => Str::title($socialDriver)]));
- }
-
- return $driver;
- }
-
- /**
- * Check a social driver has been configured correctly.
- */
- protected function checkDriverConfigured(string $driver): bool
- {
- $lowerName = strtolower($driver);
- $configPrefix = 'services.' . $lowerName . '.';
- $config = [config($configPrefix . 'client_id'), config($configPrefix . 'client_secret'), config('services.callback_url')];
-
- return !in_array(false, $config) && !in_array(null, $config);
- }
-
- /**
- * Gets the names of the active social drivers.
- * @returns array<string, string>
- */
- public function getActiveDrivers(): array
- {
- $activeDrivers = [];
-
- foreach ($this->validSocialDrivers as $driverKey) {
- if ($this->checkDriverConfigured($driverKey)) {
- $activeDrivers[$driverKey] = $this->getDriverName($driverKey);
- }
- }
-
- return $activeDrivers;
- }
-
- /**
- * Get the presentational name for a driver.
- */
- public function getDriverName(string $driver): string
- {
- return config('services.' . strtolower($driver) . '.name');
- }
-
- /**
- * Check if the current config for the given driver allows auto-registration.
- */
- public function driverAutoRegisterEnabled(string $driver): bool
- {
- return config('services.' . strtolower($driver) . '.auto_register') === true;
- }
-
- /**
- * Check if the current config for the given driver allow email address auto-confirmation.
- */
- public function driverAutoConfirmEmailEnabled(string $driver): bool
- {
- return config('services.' . strtolower($driver) . '.auto_confirm') === true;
+ return $this->driverManager;
}
/**
$driver->with(['prompt' => 'select_account']);
}
- if (isset($this->configureForRedirectCallbacks[$driverName])) {
- $this->configureForRedirectCallbacks[$driverName]($driver);
- }
+ $this->driverManager->getConfigureForRedirectCallback($driverName)($driver);
return $driver;
}
-
- /**
- * Add a custom socialite driver to be used.
- * Driver name should be lower_snake_case.
- * Config array should mirror the structure of a service
- * within the `Config/services.php` file.
- * Handler should be a Class@method handler to the SocialiteWasCalled event.
- */
- public function addSocialDriver(
- string $driverName,
- array $config,
- string $socialiteHandler,
- callable $configureForRedirect = null
- ) {
- $this->validSocialDrivers[] = $driverName;
- config()->set('services.' . $driverName, $config);
- config()->set('services.' . $driverName . '.redirect', url('/login/service/' . $driverName . '/callback'));
- config()->set('services.' . $driverName . '.name', $config['name'] ?? $driverName);
- Event::listen(SocialiteWasCalled::class, $socialiteHandler);
- if (!is_null($configureForRedirect)) {
- $this->configureForRedirectCallbacks[$driverName] = $configureForRedirect;
- }
- }
}
--- /dev/null
+<?php
+
+namespace BookStack\Access;
+
+use BookStack\Exceptions\SocialDriverNotConfigured;
+use Illuminate\Support\Facades\Event;
+use Illuminate\Support\Str;
+use SocialiteProviders\Manager\SocialiteWasCalled;
+
+class SocialDriverManager
+{
+ /**
+ * The default built-in social drivers we support.
+ *
+ * @var string[]
+ */
+ protected array $validDrivers = [
+ 'google',
+ 'github',
+ 'facebook',
+ 'slack',
+ 'twitter',
+ 'azure',
+ 'okta',
+ 'gitlab',
+ 'twitch',
+ 'discord',
+ ];
+
+ /**
+ * Callbacks to run when configuring a social driver
+ * for an initial redirect action.
+ * Array is keyed by social driver name.
+ * Callbacks are passed an instance of the driver.
+ *
+ * @var array<string, callable>
+ */
+ protected array $configureForRedirectCallbacks = [];
+
+ /**
+ * Check if the current config for the given driver allows auto-registration.
+ */
+ public function isAutoRegisterEnabled(string $driver): bool
+ {
+ return $this->getDriverConfigProperty($driver, 'auto_register') === true;
+ }
+
+ /**
+ * Check if the current config for the given driver allow email address auto-confirmation.
+ */
+ public function isAutoConfirmEmailEnabled(string $driver): bool
+ {
+ return $this->getDriverConfigProperty($driver, 'auto_confirm') === true;
+ }
+
+ /**
+ * Gets the names of the active social drivers, keyed by driver id.
+ * @returns array<string, string>
+ */
+ public function getActive(): array
+ {
+ $activeDrivers = [];
+
+ foreach ($this->validDrivers as $driverKey) {
+ if ($this->checkDriverConfigured($driverKey)) {
+ $activeDrivers[$driverKey] = $this->getName($driverKey);
+ }
+ }
+
+ return $activeDrivers;
+ }
+
+ /**
+ * Get the configure-for-redirect callback for the given driver.
+ * This is a callable that allows modification of the driver at redirect time.
+ * Commonly used to perform custom dynamic configuration where required.
+ * The callback is passed a \Laravel\Socialite\Contracts\Provider instance.
+ */
+ public function getConfigureForRedirectCallback(string $driver): callable
+ {
+ return $this->configureForRedirectCallbacks[$driver] ?? (fn() => true);
+ }
+
+ /**
+ * Add a custom socialite driver to be used.
+ * Driver name should be lower_snake_case.
+ * Config array should mirror the structure of a service
+ * within the `Config/services.php` file.
+ * Handler should be a Class@method handler to the SocialiteWasCalled event.
+ */
+ public function addSocialDriver(
+ string $driverName,
+ array $config,
+ string $socialiteHandler,
+ callable $configureForRedirect = null
+ ) {
+ $this->validDrivers[] = $driverName;
+ config()->set('services.' . $driverName, $config);
+ config()->set('services.' . $driverName . '.redirect', url('/login/service/' . $driverName . '/callback'));
+ config()->set('services.' . $driverName . '.name', $config['name'] ?? $driverName);
+ Event::listen(SocialiteWasCalled::class, $socialiteHandler);
+ if (!is_null($configureForRedirect)) {
+ $this->configureForRedirectCallbacks[$driverName] = $configureForRedirect;
+ }
+ }
+
+ /**
+ * Get the presentational name for a driver.
+ */
+ protected function getName(string $driver): string
+ {
+ return $this->getDriverConfigProperty($driver, 'name') ?? '';
+ }
+
+ protected function getDriverConfigProperty(string $driver, string $property): mixed
+ {
+ return config("services.{$driver}.{$property}");
+ }
+
+ /**
+ * Ensure the social driver is correct and supported.
+ *
+ * @throws SocialDriverNotConfigured
+ */
+ public function ensureDriverActive(string $driverName): void
+ {
+ if (!in_array($driverName, $this->validDrivers)) {
+ abort(404, trans('errors.social_driver_not_found'));
+ }
+
+ if (!$this->checkDriverConfigured($driverName)) {
+ throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => Str::title($driverName)]));
+ }
+ }
+
+ /**
+ * Check a social driver has been configured correctly.
+ */
+ protected function checkDriverConfigured(string $driver): bool
+ {
+ $lowerName = strtolower($driver);
+ $configPrefix = 'services.' . $lowerName . '.';
+ $config = [config($configPrefix . 'client_id'), config($configPrefix . 'client_secret'), config('services.callback_url')];
+
+ return !in_array(false, $config) && !in_array(null, $config);
+ }
+}
namespace BookStack\App\Providers;
-use BookStack\Access\SocialAuthService;
+use BookStack\Access\SocialDriverManager;
use BookStack\Activity\Tools\ActivityLogger;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
public $singletons = [
'activity' => ActivityLogger::class,
SettingService::class => SettingService::class,
- SocialAuthService::class => SocialAuthService::class,
+ SocialDriverManager::class => SocialDriverManager::class,
CspService::class => CspService::class,
HttpRequestService::class => HttpRequestService::class,
];
'authorization_endpoint' => env('OIDC_AUTH_ENDPOINT', null),
'token_endpoint' => env('OIDC_TOKEN_ENDPOINT', null),
+ // OIDC RP-Initiated Logout endpoint
+ // A null value gets the URL from discovery, if active.
+ // A false value force-disables RP-Initiated Logout.
+ // A string value forces the given URL to be used.
+ 'end_session_endpoint' => env('OIDC_END_SESSION_ENDPOINT', null),
+
// Add extra scopes, upon those required, to the OIDC authentication request
// Multiple values can be provided comma seperated.
'additional_scopes' => env('OIDC_ADDITIONAL_SCOPES', null),
'user_to_groups' => env('OIDC_USER_TO_GROUPS', false),
// Attribute, within a OIDC ID token, to find group names within
'groups_claim' => env('OIDC_GROUPS_CLAIM', 'groups'),
- // When syncing groups, remove any groups that no longer match. Otherwise sync only adds new 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),
-
];
-
namespace BookStack\Theming;
-use BookStack\Access\SocialAuthService;
+use BookStack\Access\SocialDriverManager;
use BookStack\Exceptions\ThemeException;
use Illuminate\Console\Application;
use Illuminate\Console\Application as Artisan;
}
/**
- * @see SocialAuthService::addSocialDriver
+ * @see SocialDriverManager::addSocialDriver
*/
public function addSocialDriver(string $driverName, array $config, string $socialiteHandler, callable $configureForRedirect = null): void
{
- $socialAuthService = app()->make(SocialAuthService::class);
- $socialAuthService->addSocialDriver($driverName, $config, $socialiteHandler, $configureForRedirect);
+ $driverManager = app()->make(SocialDriverManager::class);
+ $driverManager->addSocialDriver($driverName, $config, $socialiteHandler, $configureForRedirect);
}
}
namespace BookStack\Users\Controllers;
-use BookStack\Access\SocialAuthService;
+use BookStack\Access\SocialDriverManager;
use BookStack\Http\Controller;
use BookStack\Permissions\PermissionApplicator;
use BookStack\Settings\UserNotificationPreferences;
/**
* Show the view for the "Access & Security" account options.
*/
- public function showAuth(SocialAuthService $socialAuthService)
+ public function showAuth(SocialDriverManager $socialDriverManager)
{
$mfaMethods = user()->mfaValues()->get()->groupBy('method');
'category' => 'auth',
'mfaMethods' => $mfaMethods,
'authMethod' => config('auth.method'),
- 'activeSocialDrivers' => $socialAuthService->getActiveDrivers(),
+ 'activeSocialDrivers' => $socialDriverManager->getActive(),
]);
}
namespace BookStack\Users\Controllers;
-use BookStack\Access\SocialAuthService;
+use BookStack\Access\SocialDriverManager;
use BookStack\Exceptions\ImageUploadException;
use BookStack\Exceptions\UserUpdateException;
use BookStack\Http\Controller;
/**
* Show the form for editing the specified user.
*/
- public function edit(int $id, SocialAuthService $socialAuthService)
+ public function edit(int $id, SocialDriverManager $socialDriverManager)
{
$this->checkPermission('users-manage');
$user->load(['apiTokens', 'mfaValues']);
$authMethod = ($user->system_name) ? 'system' : config('auth.method');
- $activeSocialDrivers = $socialAuthService->getActiveDrivers();
+ $activeSocialDrivers = $socialDriverManager->getActive();
$mfaMethods = $user->mfaValues->groupBy('method');
$this->setPageTitle(trans('settings.user_profile'));
$roles = Role::query()->orderBy('display_name', 'asc')->get();
</li>
<li><hr></li>
<li>
- <?php
-// OIDC Logout Feature: Use /oidc/logout if authentication method is oidc.
- if (config('auth.method') === 'oidc') {
- ?>
- <form action="/oidc/logout"
- method="get">
- <?php
-// OIDC Logout Feature: Use /oidc/logout if authentication method is oidc.
- } else {
- ?>
- <form action="{{ url(config('auth.method') === 'saml2' ? '/saml2/logout' : '/logout') }}"
- method="post">
- <?php
-// OIDC Logout Feature: Use /oidc/logout if authentication method is oidc.
- }
- ?>
- {{ csrf_field() }}
- <button class="icon-item" data-shortcut="logout">
- @icon('logout')
- <div>{{ trans('auth.logout') }}</div>
- </button>
- </form>
+ @php
+ $logoutPath = match (config('auth.method')) {
+ 'saml2' => '/saml2/logout',
+ 'oidc' => '/oidc/logout',
+ default => '/logout',
+ }
+ @endphp
+ <form action="{{ url($logoutPath) }}" method="post">
+ {{ csrf_field() }}
+ <button class="icon-item" data-shortcut="logout">
+ @icon('logout')
+ <div>{{ trans('auth.logout') }}</div>
+ </button>
+ </form>
</li>
</ul>
</div>
\ No newline at end of file
// OIDC routes
Route::post('/oidc/login', [AccessControllers\OidcController::class, 'login']);
Route::get('/oidc/callback', [AccessControllers\OidcController::class, 'callback']);
-// OIDC Logout Feature: Added to cater OIDC logout
-Route::get('/oidc/logout', [AccessControllers\OidcController::class, 'logout']);
+Route::post('/oidc/logout', [AccessControllers\OidcController::class, 'logout']);
// User invitation routes
Route::get('/register/invite/{token}', [AccessControllers\UserInviteController::class, 'showSetPassword']);