diff --git a/modules/core/config/routes/routes.yaml b/modules/core/config/routes/routes.yaml
index 70d69139583f9871d62d28f60bb7350041729cc5..6bb06836eab8e67b4f44d040a53f43bfee7aa71a 100644
--- a/modules/core/config/routes/routes.yaml
+++ b/modules/core/config/routes/routes.yaml
@@ -7,3 +7,12 @@ core-account:
 core-logout:
     path:       /logout/{as}
     defaults:   { _controller: 'SimpleSAML\Module\core\Controller\LoginController:logout' }
+core-error-nocookie:
+    path:       /error/nocookie
+    defaults:   { _controller: 'SimpleSAML\Module\core\Controller\ExceptionController:nocookie' }
+core-cardinality:
+    path:       /error/cardinality
+    defaults:   { _controller: 'SimpleSAML\Module\core\Controller\ExceptionController:cardinality' }
+core-warning-shortssointerval:
+    path:       /warning/short_sso_interval
+    defaults:   { _controller: 'SimpleSAML\Module\core\Controller\ExceptionController:shortSsoInterval' }
diff --git a/modules/core/lib/Controller/ExceptionController.php b/modules/core/lib/Controller/ExceptionController.php
new file mode 100644
index 0000000000000000000000000000000000000000..c20bc4bc69f751780deaaa960147c14911f1502d
--- /dev/null
+++ b/modules/core/lib/Controller/ExceptionController.php
@@ -0,0 +1,157 @@
+<?php
+
+namespace SimpleSAML\Module\core\Controller;
+
+use SimpleSAML\Auth;
+use SimpleSAML\Configuration;
+use SimpleSAML\Error;
+use SimpleSAML\Logger;
+use SimpleSAML\Module;
+use SimpleSAML\Session;
+use SimpleSAML\Utils;
+use SimpleSAML\XHTML\Template;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Controller class for the core module.
+ *
+ * This class serves the different views available in the module.
+ *
+ * @package SimpleSAML\Module\core
+ */
+class ExceptionController
+{
+    /** @var \SimpleSAML\Configuration */
+    protected $config;
+
+    /** @var \SimpleSAML\Session */
+    protected $session;
+
+
+    /**
+     * Controller constructor.
+     *
+     * It initializes the global configuration and auth source configuration for the controllers implemented here.
+     *
+     * @param \SimpleSAML\Configuration              $config The configuration to use by the controllers.
+     * @param \SimpleSAML\Session                    $session The session to use by the controllers.
+     *
+     * @throws \Exception
+     */
+    public function __construct(
+        Configuration $config,
+        Session $session
+    ) {
+        $this->config = $config;
+        $this->session = $session;
+    }
+
+
+    /**
+     * Show cardinality error.
+     *
+     * @param Request $request The request that lead to this login operation.
+     * @throws \SimpleSAML\Error\BadRequest
+     * @return \SimpleSAML\XHTML\Template|\Symfony\Component\HttpFoundation\RedirectResponse
+     *   An HTML template or a redirection if we are not authenticated.
+     */
+    public function cardinality(Request $request)
+    {
+        $stateId = $request->get('StateId', false);
+        if ($stateId === false) {
+            throw new Error\BadRequest('Missing required StateId query parameter.');
+        }
+
+        /** @var array $state */
+        $state = Auth\State::loadState($stateId, 'core:cardinality');
+
+        Logger::stats(
+            'core:cardinality:error '.$state['Destination']['entityid'].' '.$state['saml:sp:IdP'].
+            ' '.implode(',', array_keys($state['core:cardinality:errorAttributes']))
+        );
+
+        $t = new Template($this->config, 'core:cardinality_error.tpl.php');
+        $t->data['cardinalityErrorAttributes'] = $state['core:cardinality:errorAttributes'];
+        if (isset($state['Source']['auth'])) {
+            $t->data['LogoutURL'] = Module::getModuleURL(
+                'core/authenticate.php',
+                ['as' => $state['Source']['auth']]
+            )."&logout";
+        }
+
+        $t->setStatusCode(403);
+        return $t;
+    }
+
+
+    /**
+     * Show missing cookie error.
+     *
+     * @param Request $request The request that lead to this login operation.
+     * @return \SimpleSAML\XHTML\Template|\Symfony\Component\HttpFoundation\RedirectResponse
+     *   An HTML template or a redirection if we are not authenticated.
+     */
+    public function nocookie(Request $request)
+    {
+        $retryURL = $request->get('retryURL', null);
+        if ($retryURL !== null) {
+            $retryURL = Utils\HTTP::checkURLAllowed(strval($retryURL));
+        }
+
+        $t = new Template($this->config, 'core:no_cookie.tpl.php');
+        $translator = $t->getTranslator();
+
+        /** @var string $header */
+        $header = $translator->t('{core:no_cookie:header}');
+
+        /** @var string $desc */
+        $desc = $translator->t('{core:no_cookie:description}');
+
+        /** @var string $retry */
+        $retry = $translator->t('{core:no_cookie:retry}');
+
+        $t->data['header'] = htmlspecialchars($header);
+        $t->data['description'] = htmlspecialchars($desc);
+        $t->data['retry'] = htmlspecialchars($retry);
+        $t->data['retryURL'] = $retryURL;
+        return $t;
+    }
+
+
+    /**
+     * Show a warning to an user about the SP requesting SSO a short time after
+     * doing it previously.
+     *
+     * @param Request $request The request that lead to this login operation.
+     *
+     * @return \SimpleSAML\XHTML\Template|\SimpleSAML\HTTP\RunnableResponse|\Symfony\Component\HttpFoundation\RedirectResponse
+     * An HTML template, a redirect or a "runnable" response.
+     *
+     * @throws \SimpleSAML\Error\BadRequest
+     */
+    public function shortSsoInterval(Request $request)
+    {
+        $stateId = $request->get('StateId', false);
+        if ($stateId === false) {
+            throw new Error\BadRequest('Missing required StateId query parameter.');
+        }
+
+        /** @var array $state */
+        $state = Auth\State::loadState($stateId, 'core:short_sso_interval');
+
+        $continue = $request->get('continue', false);
+        if ($continue !== false) {
+            // The user has pressed the continue/retry-button
+            Auth\ProcessingChain::resumeProcessing($state);
+        }
+
+        $t = new Template($this->config, 'core:short_sso_interval.tpl.php');
+        $translator = $t->getTranslator();
+        $t->data['target'] = Module::getModuleURL('core/short_sso_interval.php');
+        $t->data['params'] = ['StateId' => $stateId];
+        $t->data['trackId'] = $this->session->getTrackID();
+        $t->data['header'] = $translator->t('{core:short_sso_interval:warning_header}');
+        $t->data['autofocus'] = 'contbutton';
+        return $t;
+    }
+}