diff --git a/app/Auth/Access/Saml2Service.php b/app/Auth/Access/Saml2Service.php
index a5ca54c8d..a9441dc40 100644
--- a/app/Auth/Access/Saml2Service.php
+++ b/app/Auth/Access/Saml2Service.php
@@ -4,10 +4,12 @@ use BookStack\Auth\User;
 use BookStack\Auth\UserRepo;
 use BookStack\Exceptions\JsonDebugException;
 use BookStack\Exceptions\SamlException;
+use Exception;
 use Illuminate\Support\Str;
 use OneLogin\Saml2\Auth;
 use OneLogin\Saml2\Error;
 use OneLogin\Saml2\IdPMetadataParser;
+use OneLogin\Saml2\ValidationError;
 
 /**
  * Class Saml2Service
@@ -33,7 +35,7 @@ class Saml2Service extends ExternalAuthService
 
     /**
      * Initiate a login flow.
-     * @throws \OneLogin\Saml2\Error
+     * @throws Error
      */
     public function login(): array
     {
@@ -45,25 +47,50 @@ class Saml2Service extends ExternalAuthService
         ];
     }
 
+    /**
+     * Initiate a logout flow.
+     * @throws Error
+     */
+    public function logout(): array
+    {
+        $toolKit = $this->getToolkit();
+        $returnRoute = url('/');
+
+        try {
+            $url = $toolKit->logout($returnRoute, [], null, null, true);
+            $id = $toolKit->getLastRequestID();
+        } catch (Error $error) {
+            if ($error->getCode() !== Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED) {
+                throw $error;
+            }
+
+            $this->actionLogout();
+            $url = '/';
+            $id = null;
+        }
+
+        return ['url' => $url, 'id' => $id];
+    }
+
     /**
      * Process the ACS response from the idp and return the
      * matching, or new if registration active, user matched to the idp.
      * Returns null if not authenticated.
      * @throws Error
      * @throws SamlException
-     * @throws \OneLogin\Saml2\ValidationError
+     * @throws ValidationError
      * @throws JsonDebugException
      */
     public function processAcsResponse(?string $requestId): ?User
     {
-        $toolkit = $this->getToolkit();
-        $toolkit->processResponse($requestId);
-        $errors = $toolkit->getErrors();
-
         if (is_null($requestId)) {
             throw new SamlException(trans('errors.saml_invalid_response_id'));
         }
 
+        $toolkit = $this->getToolkit();
+        $toolkit->processResponse($requestId);
+        $errors = $toolkit->getErrors();
+
         if (!empty($errors)) {
             throw new Error(
                 'Invalid ACS Response: '.implode(', ', $errors)
@@ -80,6 +107,36 @@ class Saml2Service extends ExternalAuthService
         return $this->processLoginCallback($id, $attrs);
     }
 
+    /**
+     * Process a response for the single logout service.
+     * @throws Error
+     */
+    public function processSlsResponse(?string $requestId): ?string
+    {
+        $toolkit = $this->getToolkit();
+        $redirect = $toolkit->processSLO(true, $requestId, false, null, true);
+
+        $errors = $toolkit->getErrors();
+
+        if (!empty($errors)) {
+            throw new Error(
+                'Invalid SLS Response: '.implode(', ', $errors)
+            );
+        }
+
+        $this->actionLogout();
+        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.
      * @throws Error
@@ -103,8 +160,8 @@ class Saml2Service extends ExternalAuthService
 
     /**
      * Load the underlying Onelogin SAML2 toolkit.
-     * @throws \OneLogin\Saml2\Error
-     * @throws \Exception
+     * @throws Error
+     * @throws Exception
      */
     protected function getToolkit(): Auth
     {
diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php
index 477d3d26b..b1d22d57e 100644
--- a/app/Http/Controllers/Auth/LoginController.php
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -146,4 +146,23 @@ class LoginController extends Controller
         session()->put('social-callback', 'login');
         return $this->socialAuthService->startLogIn($socialDriver);
     }
+
+    /**
+     * Log the user out of the application.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function logout(Request $request)
+    {
+        if (config('saml2.enabled') && session()->get('last_login_type') === 'saml2') {
+            return redirect('/saml2/logout');
+        }
+
+        $this->guard()->logout();
+
+        $request->session()->invalidate();
+
+        return $this->loggedOut($request) ?: redirect('/');
+    }
 }
diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php
index d54e925bb..c32f19c5e 100644
--- a/app/Http/Controllers/Auth/Saml2Controller.php
+++ b/app/Http/Controllers/Auth/Saml2Controller.php
@@ -31,6 +31,20 @@ class Saml2Controller extends Controller
         return redirect($loginDetails['url']);
     }
 
+    /**
+     * Start the logout flow via SAML2.
+     */
+    public function logout()
+    {
+        $logoutDetails = $this->samlService->logout();
+
+        if ($logoutDetails['id']) {
+            session()->flash('saml2_logout_request_id', $logoutDetails['id']);
+        }
+
+        return redirect($logoutDetails['url']);
+    }
+
     /*
      * Get the metadata for this SAML2 service provider.
      */
@@ -48,7 +62,9 @@ class Saml2Controller extends Controller
      */
     public function sls()
     {
-        // TODO
+        $requestId = session()->pull('saml2_logout_request_id', null);
+        $redirect = $this->samlService->processSlsResponse($requestId) ?? '/';
+        return redirect($redirect);
     }
 
     /**
@@ -65,6 +81,7 @@ class Saml2Controller extends Controller
             return redirect('/login');
         }
 
+        session()->put('last_login_type', 'saml2');
         return redirect()->intended();
     }
 
diff --git a/routes/web.php b/routes/web.php
index 461d3c1aa..0c554bf8e 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -219,8 +219,7 @@ Route::post('/register', 'Auth\RegisterController@postRegister');
 // SAML routes
 // TODO - Prevent access without SAML2 enabled via middleware
 Route::get('/saml2/login', 'Auth\Saml2Controller@login');
-// TODO - Handle logout?
-//    Route::get('/saml2/logout', 'Auth\Saml2Controller@logout');
+Route::get('/saml2/logout', 'Auth\Saml2Controller@logout');
 Route::get('/saml2/metadata', 'Auth\Saml2Controller@metadata');
 Route::get('/saml2/sls', 'Auth\Saml2Controller@sls');
 Route::post('/saml2/acs', 'Auth\Saml2Controller@acs');