diff --git a/lib/SimpleSAML/Auth/Simple.php b/lib/SimpleSAML/Auth/Simple.php
index ca806d3759652af6fc2caa80233349612daa9efa..552550d33e7b433cb417df070918e5aca04e4145 100644
--- a/lib/SimpleSAML/Auth/Simple.php
+++ b/lib/SimpleSAML/Auth/Simple.php
@@ -385,7 +385,7 @@ class Simple
             $port = '';
         }
 
-        $base = trim($this->app_config->getString(
+        $base = trim($this->app_config->getOptionalString(
             'baseURL',
             $scheme . '://' . $host . $port
         ), '/');
diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php
index 54262ac859fa1b6a4194b6f1019bb30219a45779..e20140ac7fb08dd92ac0fca3690b00e20e0c58ba 100644
--- a/lib/SimpleSAML/Configuration.php
+++ b/lib/SimpleSAML/Configuration.php
@@ -428,7 +428,7 @@ class Configuration implements Utils\ClearableState
      */
     public function getBasePath(): string
     {
-        $baseURL = $this->getString('baseurlpath', 'simplesaml/');
+        $baseURL = $this->getOptionalString('baseurlpath', 'simplesaml/');
 
         if (preg_match('#^https?://[^/]*(?:/(.+/?)?)?$#', $baseURL, $matches)) {
             // we have a full url, we need to strip the path
@@ -453,7 +453,7 @@ class Configuration implements Utils\ClearableState
             $c['baseurlpath'] = $httpUtils->guessBasePath();
             throw new Error\CriticalConfigurationError(
                 'Incorrect format for option \'baseurlpath\'. Value is: "' .
-                $this->getString('baseurlpath', 'simplesaml/') . '". Valid format is in the form' .
+                $this->getOptionalString('baseurlpath', 'simplesaml/') . '". Valid format is in the form' .
                 ' [(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/].',
                 $this->filename,
                 $c
@@ -527,7 +527,7 @@ class Configuration implements Utils\ClearableState
     public function getBaseDir(): string
     {
         // check if a directory is configured in the configuration file
-        $dir = $this->getString('basedir', null);
+        $dir = $this->getOptionalString('basedir', null);
         if ($dir !== null) {
             // add trailing slash if it is missing
             if (substr($dir, -1) !== DIRECTORY_SEPARATOR) {
@@ -606,36 +606,47 @@ class Configuration implements Utils\ClearableState
     /**
      * This function retrieves a string configuration option.
      *
-     * An exception will be thrown if this option isn't a string, or if this option isn't found, and no default value
-     * is given.
+     * An exception will be thrown if this option isn't a string, or if this option isn't found.
      *
-     * @param string $name The name of the option.
-     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
-     *                  required if this parameter isn't given. The default value can be any value, including
-     *                  null.
+     * @param string $name  The name of the option.
+     * @return string       The option with the given name.
      *
-     * @return string|mixed The option with the given name, or $default if the option isn't found and $default is
-     *     specified.
-     *
-     * @throws \Exception If the option is not a string.
+     * @throws \SimpleSAML\Assert\AssertionFailedException If the option is not a string.
      */
-    public function getString(string $name, $default = self::REQUIRED_OPTION)
+    public function getString(string $name): string
     {
-        $ret = $this->getValue($name, $default);
+        $ret = $this->getValue($name);
 
-        if ($ret === $default) {
-            // the option wasn't found, or it matches the default value. In any case, return this value
-            return $ret;
-        }
+        Assert::string(
+            $ret,
+            sprintf('%s: The option %s is not a valid string value.', $this->location, var_export($name, true)),
+        );
 
-        if (!is_string($ret)) {
-            throw new \Exception(
-                $this->location . ': The option ' . var_export($name, true) .
-                ' is not a valid string value.'
-            );
+        return $ret;
+    }
+
+
+    /**
+     * This function retrieves an optional string configuration option.
+     *
+     * An exception will be thrown if this option isn't a string.
+     *
+     * @param string       $name     The name of the option.
+     * @param string|null  $default  A default value which will be returned if the option isn't found.
+     *                               The default value can be null or a string.
+     *
+     * @return string|null The option with the given name, or $default if the option isn't found.
+     *
+     * @throws \SimpleSAML\Assert\AssertionFailedException If the option is not a string.
+     */
+    public function getOptionalString(string $name, ?string $default): ?string
+    {
+        if (!$this->hasValue($name)) {
+            // the option wasn't found, or it matches the default value. In any case, return this value
+            return $default;
         }
 
-        return $ret;
+        return $this->getString($name);
     }
 
 
@@ -1009,7 +1020,7 @@ class Configuration implements Utils\ClearableState
                     'Location' => $ep,
                     'Binding'  => $this->getDefaultBinding($endpointType),
                 ];
-                $responseLocation = $this->getString($endpointType . 'Response', null);
+                $responseLocation = $this->getOptionalString($endpointType . 'Response', null);
                 if ($responseLocation !== null) {
                     $ep['ResponseLocation'] = $responseLocation;
                 }
@@ -1191,7 +1202,7 @@ class Configuration implements Utils\ClearableState
         } elseif ($this->hasValue($prefix . 'certData')) {
             $certData = $this->getString($prefix . 'certData');
             $certData = preg_replace('/\s+/', '', $certData);
-            $keyName = $this->getString($prefix . 'key_name', null);
+            $keyName = $this->getOptionalString($prefix . 'key_name', null);
             return [
                 [
                     'name'            => $keyName,
@@ -1222,7 +1233,7 @@ class Configuration implements Utils\ClearableState
                 );
             }
             $certData = preg_replace('/\s+/', '', $matches[1]);
-            $keyName = $this->getString($prefix . 'key_name', null);
+            $keyName = $this->getOptionalString($prefix . 'key_name', null);
 
             return [
                 [
diff --git a/lib/SimpleSAML/Database.php b/lib/SimpleSAML/Database.php
index 7b294897b0478e7055e79f49b0c39c258f844268..239b88eb69a7074edc45703ce0f770cc6c08cbed 100644
--- a/lib/SimpleSAML/Database.php
+++ b/lib/SimpleSAML/Database.php
@@ -92,8 +92,8 @@ class Database
         // connect to the primary
         $this->dbPrimary = $this->connect(
             $config->getString('database.dsn'),
-            $config->getString('database.username', null),
-            $config->getString('database.password', null),
+            $config->getOptionalString('database.username', null),
+            $config->getOptionalString('database.password', null),
             $driverOptions
         );
 
@@ -117,7 +117,7 @@ class Database
                 )
             );
         }
-        $this->tablePrefix = $config->getString('database.prefix', '');
+        $this->tablePrefix = $config->getOptionalString('database.prefix', '');
     }
 
 
@@ -133,9 +133,9 @@ class Database
         $assembledConfig = [
             'primary' => [
                 'database.dsn'        => $config->getString('database.dsn'),
-                'database.username'   => $config->getString('database.username', null),
-                'database.password'   => $config->getString('database.password', null),
-                'database.prefix'     => $config->getString('database.prefix', ''),
+                'database.username'   => $config->getOptionalString('database.username', null),
+                'database.password'   => $config->getOptionalString('database.password', null),
+                'database.prefix'     => $config->getOptionalString('database.prefix', ''),
                 'database.persistent' => $config->getOptionalBoolean('database.persistent', true),
             ],
 
diff --git a/lib/SimpleSAML/Error/Error.php b/lib/SimpleSAML/Error/Error.php
index 7077b7e75c6d92cb8b3f8e453956e12ae50f0eed..755bcb3c64fdaa0353d619f5a073a6ddaf9f60c1 100644
--- a/lib/SimpleSAML/Error/Error.php
+++ b/lib/SimpleSAML/Error/Error.php
@@ -243,7 +243,7 @@ class Error extends Exception
         // check if there is a valid technical contact email address
         if (
             $config->getOptionalBoolean('errorreporting', true)
-            && $config->getString('technicalcontact_email', 'na@example.org') !== 'na@example.org'
+            && $config->getOptionalString('technicalcontact_email', 'na@example.org') !== 'na@example.org'
         ) {
             // enable error reporting
             $httpUtils = new Utils\HTTP();
diff --git a/lib/SimpleSAML/IdP.php b/lib/SimpleSAML/IdP.php
index dccf0aa860c50c4e9f45a5bedfb88c02a06befd7..59fc0de1c9810f988bcccd7c17cae4b542230748 100644
--- a/lib/SimpleSAML/IdP.php
+++ b/lib/SimpleSAML/IdP.php
@@ -423,7 +423,7 @@ class IdP
     public function getLogoutHandler(): LogoutHandlerInterface
     {
         // find the logout handler
-        $logouttype = $this->getConfig()->getString('logouttype', 'traditional');
+        $logouttype = $this->getConfig()->getOptionalString('logouttype', 'traditional');
         switch ($logouttype) {
             case 'traditional':
                 $handler = TraditionalLogoutHandler::class;
diff --git a/lib/SimpleSAML/Locale/Language.php b/lib/SimpleSAML/Locale/Language.php
index d1c6a4dab78f6612f70a9bd638ef83ad02be5348..30b5e51bc99981539cf73d37428145888d4f6052 100644
--- a/lib/SimpleSAML/Locale/Language.php
+++ b/lib/SimpleSAML/Locale/Language.php
@@ -153,8 +153,8 @@ class Language
     {
         $this->configuration = $configuration;
         $this->availableLanguages = $this->getInstalledLanguages();
-        $this->defaultLanguage = $this->configuration->getString('language.default', self::FALLBACKLANGUAGE);
-        $this->languageParameterName = $this->configuration->getString('language.parameter.name', 'language');
+        $this->defaultLanguage = $this->configuration->getOptionalString('language.default', self::FALLBACKLANGUAGE);
+        $this->languageParameterName = $this->configuration->getOptionalString('language.parameter.name', 'language');
         $this->customFunction = $this->configuration->getArray('language.get_language_function', null);
         $this->rtlLanguages = $this->configuration->getArray('language.rtl', []);
         if (isset($_GET[$this->languageParameterName])) {
@@ -404,7 +404,7 @@ class Language
     {
         $config = Configuration::getInstance();
         $availableLanguages = $config->getArray('language.available', [self::FALLBACKLANGUAGE]);
-        $name = $config->getString('language.cookie.name', 'language');
+        $name = $config->getOptionalString('language.cookie.name', 'language');
 
         if (isset($_COOKIE[$name])) {
             $language = strtolower((string) $_COOKIE[$name]);
@@ -432,14 +432,14 @@ class Language
             return;
         }
 
-        $name = $config->getString('language.cookie.name', 'language');
+        $name = $config->getOptionalString('language.cookie.name', 'language');
         $params = [
             'lifetime' => ($config->getInteger('language.cookie.lifetime', 60 * 60 * 24 * 900)),
-            'domain'   => ($config->getString('language.cookie.domain', '')),
-            'path'     => ($config->getString('language.cookie.path', '/')),
+            'domain'   => ($config->getOptionalString('language.cookie.domain', '')),
+            'path'     => ($config->getOptionalString('language.cookie.path', '/')),
             'secure'   => ($config->getOptionalBoolean('language.cookie.secure', false)),
             'httponly' => ($config->getOptionalBoolean('language.cookie.httponly', false)),
-            'samesite' => ($config->getString('language.cookie.samesite', null)),
+            'samesite' => ($config->getOptionalString('language.cookie.samesite', null)),
         ];
 
         $httpUtils = new Utils\HTTP();
diff --git a/lib/SimpleSAML/Locale/Localization.php b/lib/SimpleSAML/Locale/Localization.php
index d88127b04580fdda9fd63fe67d3ccfc052e230ab..1dbb5c1f6ac6af03606ea878393755d3840308c8 100644
--- a/lib/SimpleSAML/Locale/Localization.php
+++ b/lib/SimpleSAML/Locale/Localization.php
@@ -268,7 +268,7 @@ class Localization
     {
         $this->addDomain($this->localeDir, 'attributes');
 
-        list($theme,) = explode(':', $this->configuration->getString('theme.use', 'default'));
+        list($theme,) = explode(':', $this->configuration->getOptionalString('theme.use', 'default'));
         if ($theme !== 'default') {
             $this->addModuleDomain($theme, null, 'attributes');
         }
diff --git a/lib/SimpleSAML/Logger.php b/lib/SimpleSAML/Logger.php
index c390ca82e94d2194bd95886ad619cd2d02d1be6e..c6cb9384824fa8f52e8c048fb77c9a1fd74f777a 100644
--- a/lib/SimpleSAML/Logger.php
+++ b/lib/SimpleSAML/Logger.php
@@ -453,7 +453,7 @@ class Logger
 
         // get the metadata handler option from the configuration
         if (is_null($handler)) {
-            $handler = $config->getString(
+            $handler = $config->getOptionalString(
                 'logging.handler',
                 php_sapi_name() === 'cli' || defined('STDIN') ? 'stderr' : 'syslog'
             );
@@ -473,7 +473,7 @@ class Logger
             $handler = $known_handlers[$handler];
         }
 
-        self::$format = $config->getString('logging.format', self::$format);
+        self::$format = $config->getOptionalString('logging.format', self::$format);
 
         try {
             /** @var \SimpleSAML\Logger\LoggingHandlerInterface */
diff --git a/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php b/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php
index 0ccf91d2354f3bb1262f4baabf50dbc209948c48..9c989d725e33e2dfc3d61482b2e620356d226b86 100644
--- a/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php
@@ -49,7 +49,7 @@ class ErrorLogLoggingHandler implements LoggingHandlerInterface
         $this->processname = preg_replace(
             '/[\x00-\x1F\x7F\xA0]/u',
             '',
-            $config->getString('logging.processname', 'SimpleSAMLphp')
+            $config->getOptionalString('logging.processname', 'SimpleSAMLphp')
         );
     }
 
diff --git a/lib/SimpleSAML/Logger/FileLoggingHandler.php b/lib/SimpleSAML/Logger/FileLoggingHandler.php
index ec06001f32844188d321faf2d0e556d8258910ef..179080bb2436ee1750e0c55f7a97a4ade2616aa2 100644
--- a/lib/SimpleSAML/Logger/FileLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/FileLoggingHandler.php
@@ -54,13 +54,13 @@ class FileLoggingHandler implements LoggingHandlerInterface
     {
         // get the metadata handler option from the configuration
         $this->logFile = $config->getPathValue('loggingdir', 'log/') .
-            $config->getString('logging.logfile', 'simplesamlphp.log');
+            $config->getOptionalString('logging.logfile', 'simplesamlphp.log');
 
         // Remove any non-printable characters before storing
         $this->processname = preg_replace(
             '/[\x00-\x1F\x7F\xA0]/u',
             '',
-            $config->getString('logging.processname', 'SimpleSAMLphp')
+            $config->getOptionalString('logging.processname', 'SimpleSAMLphp')
         );
 
         if (@file_exists($this->logFile)) {
diff --git a/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php b/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php
index 2083f9d3224bee76769a208a27316169b49fa682..1fd967955ee9bed379d36fc458829c19198b2d84 100644
--- a/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php
@@ -26,7 +26,7 @@ class StandardErrorLoggingHandler extends FileLoggingHandler
         $this->processname = preg_replace(
             '/[\x00-\x1F\x7F\xA0]/u',
             '',
-            $config->getString('logging.processname', 'SimpleSAMLphp')
+            $config->getOptionalString('logging.processname', 'SimpleSAMLphp')
         );
         $this->logFile = 'php://stderr';
     }
diff --git a/lib/SimpleSAML/Logger/SyslogLoggingHandler.php b/lib/SimpleSAML/Logger/SyslogLoggingHandler.php
index cdfcf0aa3686c1c6cad259ebb8cc544777547d86..9f7afb60c161640ef3c0e95e60cc03aa4c1a55b5 100644
--- a/lib/SimpleSAML/Logger/SyslogLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/SyslogLoggingHandler.php
@@ -33,7 +33,7 @@ class SyslogLoggingHandler implements LoggingHandlerInterface
         $processname = preg_replace(
             '/[\x00-\x1F\x7F\xA0]/u',
             '',
-            $config->getString('logging.processname', 'SimpleSAMLphp')
+            $config->getOptionalString('logging.processname', 'SimpleSAMLphp')
         );
 
         // Setting facility to LOG_USER (only valid in Windows), enable log level rewrite on windows systems
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
index c687b01a8dca7c752db20635b8b9fc7815651301..5d8727e759916452e4368e549dd4a1141316abf8 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
@@ -70,7 +70,7 @@ class MetaDataStorageHandler implements ClearableState
 
         // for backwards compatibility, and to provide a default configuration
         if ($sourcesConfig === null) {
-            $type = $config->getString('metadata.handler', 'flatfile');
+            $type = $config->getOptionalString('metadata.handler', 'flatfile');
             $sourcesConfig = [['type' => $type]];
         }
 
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php
index 3f6e9c5090ec78fffcc7ce930d765e0dcff0ebf2..8b1f39b0a256d01c8de964d1ca2852ef815ac1b8 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php
@@ -52,7 +52,7 @@ class MetaDataStorageHandlerFlatFile extends MetaDataStorageSource
         if (array_key_exists('directory', $config)) {
             $this->directory = $config['directory'] ?: 'metadata/';
         } else {
-            $this->directory = $globalConfig->getString('metadatadir', 'metadata/');
+            $this->directory = $globalConfig->getOptionalString('metadatadir', 'metadata/');
         }
 
         /* Resolve this directory relative to the SimpleSAMLphp directory (unless it is
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
index 5f371e28f23da75c6f20da0d01239490a6df0e31..1dcf7d1cf19265f523bbd52617e4dd0a64d6654c 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
@@ -45,7 +45,6 @@ class MetaDataStorageHandlerSerialize extends MetaDataStorageSource
         $globalConfig = Configuration::getInstance();
 
         $cfgHelp = Configuration::loadFromArray($config, 'serialize metadata source');
-var_dump($config);
         $this->directory = $cfgHelp->getString('directory');
 
         /* Resolve this directory relative to the SimpleSAMLphp directory (unless it is
diff --git a/lib/SimpleSAML/Metadata/SAMLBuilder.php b/lib/SimpleSAML/Metadata/SAMLBuilder.php
index 14c8e02a058bc2ae43ca2462c1f94d619bc3aafb..d0bfd6e0a01dc8277ded8cb81823317c7b8475ed 100644
--- a/lib/SimpleSAML/Metadata/SAMLBuilder.php
+++ b/lib/SimpleSAML/Metadata/SAMLBuilder.php
@@ -437,7 +437,7 @@ class SAMLBuilder
         $attributeconsumer->setServiceName($name);
         $attributeconsumer->setServiceDescription($metadata->getLocalizedString('description', []));
 
-        $nameFormat = $metadata->getString('attributes.NameFormat', Constants::NAMEFORMAT_URI);
+        $nameFormat = $metadata->getOptionalString('attributes.NameFormat', Constants::NAMEFORMAT_URI);
         foreach ($attributes as $friendlyName => $attribute) {
             $t = new RequestedAttribute();
             $t->setName($attribute);
diff --git a/lib/SimpleSAML/Metadata/Signer.php b/lib/SimpleSAML/Metadata/Signer.php
index 2e056e324c8b551a92cd77ec5f6112c4c5dcb995..10dd1208a74805265e7be1ad8d3edcca5225be54 100644
--- a/lib/SimpleSAML/Metadata/Signer.php
+++ b/lib/SimpleSAML/Metadata/Signer.php
@@ -62,8 +62,8 @@ class Signer
         }
 
         // then we look for default values in the global configuration
-        $privatekey = $config->getString('metadata.sign.privatekey', null);
-        $certificate = $config->getString('metadata.sign.certificate', null);
+        $privatekey = $config->getOptionalString('metadata.sign.privatekey', null);
+        $certificate = $config->getOptionalString('metadata.sign.certificate', null);
         if ($privatekey !== null || $certificate !== null) {
             if ($privatekey === null || $certificate === null) {
                 throw new \Exception(
@@ -75,7 +75,7 @@ class Signer
             }
             $ret = ['privatekey' => $privatekey, 'certificate' => $certificate];
 
-            $privatekey_pass = $config->getString('metadata.sign.privatekey_pass', null);
+            $privatekey_pass = $config->getOptionalString('metadata.sign.privatekey_pass', null);
             if ($privatekey_pass !== null) {
                 $ret['privatekey_pass'] = $privatekey_pass;
             }
@@ -178,7 +178,7 @@ class Signer
             }
             $alg = $entityMetadata['metadata.sign.algorithm'];
         } else {
-            $alg = $config->getString('metadata.sign.algorithm', XMLSecurityKey::RSA_SHA256);
+            $alg = $config->getOptionalString('metadata.sign.algorithm', XMLSecurityKey::RSA_SHA256);
         }
 
         $supported_algs = [
diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php
index 260289ff218e9751de6019db5e77f2d60182db88..f108f8e56eba31c2a35154769e2d39e90e68600d 100644
--- a/lib/SimpleSAML/Session.php
+++ b/lib/SimpleSAML/Session.php
@@ -355,7 +355,7 @@ class Session implements Utils\ClearableState
             $globalConfig = Configuration::getInstance();
 
             if ($session->authToken !== null) {
-                $authTokenCookieName = $globalConfig->getString(
+                $authTokenCookieName = $globalConfig->getOptionalString(
                     'session.authtoken.cookiename',
                     'SimpleSAMLAuthToken'
                 );
@@ -660,7 +660,7 @@ class Session implements Utils\ClearableState
             $httpUtils = new Utils\HTTP();
             try {
                 $httpUtils->setCookie(
-                    self::$config->getString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'),
+                    self::$config->getOptionalString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'),
                     $this->authToken,
                     $sessionHandler->getCookieParams()
                 );
@@ -790,7 +790,7 @@ class Session implements Utils\ClearableState
         if ($this->authToken !== null) {
             $httpUtils = new Utils\HTTP();
             $httpUtils->setCookie(
-                self::$config->getString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'),
+                self::$config->getOptionalString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'),
                 $this->authToken,
                 $params
             );
diff --git a/lib/SimpleSAML/SessionHandler.php b/lib/SimpleSAML/SessionHandler.php
index 1e3e1344b6fb2fec42f398ad8cb70c5430f95a4f..402631f6d726236543ab4cb94d5a455e8f4c5ed0 100644
--- a/lib/SimpleSAML/SessionHandler.php
+++ b/lib/SimpleSAML/SessionHandler.php
@@ -136,7 +136,7 @@ abstract class SessionHandler
     private static function createSessionHandler(): void
     {
         $config = Configuration::getInstance();
-        $storeType = $config->getString('store.type', 'phpsession');
+        $storeType = $config->getOptionalString('store.type', 'phpsession');
 
         $store = StoreFactory::getInstance($storeType);
         if ($store === false) {
@@ -159,10 +159,10 @@ abstract class SessionHandler
 
         return [
             'lifetime' => $config->getInteger('session.cookie.lifetime', 0),
-            'path'     => $config->getString('session.cookie.path', '/'),
-            'domain'   => $config->getString('session.cookie.domain', null),
+            'path'     => $config->getOptionalString('session.cookie.path', '/'),
+            'domain'   => $config->getOptionalString('session.cookie.domain', null),
             'secure'   => $config->getOptionalBoolean('session.cookie.secure', false),
-            'samesite' => $config->getString('session.cookie.samesite', null),
+            'samesite' => $config->getOptionalString('session.cookie.samesite', null),
             'httponly' => true,
         ];
     }
diff --git a/lib/SimpleSAML/SessionHandlerCookie.php b/lib/SimpleSAML/SessionHandlerCookie.php
index 86bad84468289287e7ec569af70858ea43d60135..1c0d2223c4c36fb826d3dc239a7e3cfad8964eec 100644
--- a/lib/SimpleSAML/SessionHandlerCookie.php
+++ b/lib/SimpleSAML/SessionHandlerCookie.php
@@ -45,7 +45,7 @@ abstract class SessionHandlerCookie extends SessionHandler
         parent::__construct();
 
         $config = Configuration::getInstance();
-        $this->cookie_name = $config->getString('session.cookie.name', 'SimpleSAMLSessionID');
+        $this->cookie_name = $config->getOptionalString('session.cookie.name', 'SimpleSAMLSessionID');
     }
 
 
diff --git a/lib/SimpleSAML/SessionHandlerPHP.php b/lib/SimpleSAML/SessionHandlerPHP.php
index b1dd93aad102fba3f5851db9480b09c069298d48..b8e83a88588bca95bde6dad9f9b34fbddc513644 100644
--- a/lib/SimpleSAML/SessionHandlerPHP.php
+++ b/lib/SimpleSAML/SessionHandlerPHP.php
@@ -48,7 +48,7 @@ class SessionHandlerPHP extends SessionHandler
         parent::__construct();
 
         $config = Configuration::getInstance();
-        $this->cookie_name = $config->getString(
+        $this->cookie_name = $config->getOptionalString(
             'session.phpsession.cookiename',
             ini_get('session.name') ?: 'PHPSESSID'
         );
@@ -92,7 +92,7 @@ class SessionHandlerPHP extends SessionHandler
             ]);
         }
 
-        $savepath = $config->getString('session.phpsession.savepath', null);
+        $savepath = $config->getOptionalString('session.phpsession.savepath', null);
         if (!empty($savepath)) {
             session_save_path($savepath);
         }
diff --git a/lib/SimpleSAML/Store/MemcacheStore.php b/lib/SimpleSAML/Store/MemcacheStore.php
index b67a1f8acd774b21e1c53082d3057a013101aee7..0c74907e24fac174be77d025705998229347f467 100644
--- a/lib/SimpleSAML/Store/MemcacheStore.php
+++ b/lib/SimpleSAML/Store/MemcacheStore.php
@@ -29,7 +29,7 @@ class MemcacheStore implements StoreInterface
     public function __construct()
     {
         $config = Configuration::getInstance();
-        $this->prefix = $config->getString('memcache_store.prefix', 'simpleSAMLphp');
+        $this->prefix = $config->getOptionalString('memcache_store.prefix', 'simpleSAMLphp');
     }
 
 
diff --git a/lib/SimpleSAML/Store/RedisStore.php b/lib/SimpleSAML/Store/RedisStore.php
index d78871fb6dfc4fb1dd9f8c8b24419f6de1824957..53f08675c948a15b3a3293741ba420066681a04b 100644
--- a/lib/SimpleSAML/Store/RedisStore.php
+++ b/lib/SimpleSAML/Store/RedisStore.php
@@ -35,10 +35,10 @@ class RedisStore implements StoreInterface
         if ($redis === null) {
             $config = Configuration::getInstance();
 
-            $host = $config->getString('store.redis.host', 'localhost');
+            $host = $config->getOptionalString('store.redis.host', 'localhost');
             $port = $config->getInteger('store.redis.port', 6379);
-            $prefix = $config->getString('store.redis.prefix', 'SimpleSAMLphp');
-            $password = $config->getString('store.redis.password', '');
+            $prefix = $config->getOptionalString('store.redis.prefix', 'SimpleSAMLphp');
+            $password = $config->getOptionalString('store.redis.password', null);
             $database = $config->getInteger('store.redis.database', 0);
 
             $redis = new Client(
diff --git a/lib/SimpleSAML/Utils/Config/Metadata.php b/lib/SimpleSAML/Utils/Config/Metadata.php
index 517a155245ac26c47db0821848659795aeb4ffac..f7a1a389aaa29328fb81157b4a51a641a1f0ca0f 100644
--- a/lib/SimpleSAML/Utils/Config/Metadata.php
+++ b/lib/SimpleSAML/Utils/Config/Metadata.php
@@ -277,11 +277,11 @@ class Metadata
             // handle current configurations specifying an array in the NameIDPolicy config option
             $nameIdPolicy_cf = Configuration::loadFromArray($nameIdPolicy);
             $policy = [
-                'Format'      => $nameIdPolicy_cf->getString('Format', Constants::NAMEID_TRANSIENT),
+                'Format'      => $nameIdPolicy_cf->getOptionalString('Format', Constants::NAMEID_TRANSIENT),
                 'AllowCreate' => $nameIdPolicy_cf->getOptionalBoolean('AllowCreate', true),
             ];
-            $spNameQualifier = $nameIdPolicy_cf->getString('SPNameQualifier', false);
-            if ($spNameQualifier !== false) {
+            $spNameQualifier = $nameIdPolicy_cf->getOptionalString('SPNameQualifier', null);
+            if ($spNameQualifier !== null) {
                 $policy['SPNameQualifier'] = $spNameQualifier;
             }
         } elseif ($nameIdPolicy === null) {
diff --git a/lib/SimpleSAML/Utils/Crypto.php b/lib/SimpleSAML/Utils/Crypto.php
index 0be2ec3ee136158723abd9f7977f952124cb34d2..5d741a4b1df67c80e0d165be5e953a36d587e175 100644
--- a/lib/SimpleSAML/Utils/Crypto.php
+++ b/lib/SimpleSAML/Utils/Crypto.php
@@ -203,7 +203,7 @@ class Crypto
         string $prefix = '',
         bool $full_path = false
     ): ?array {
-        $file = $metadata->getString($prefix . 'privatekey', null);
+        $file = $metadata->getOptionalString($prefix . 'privatekey', null);
         if ($file === null) {
             // no private key found
             if ($required) {
@@ -225,7 +225,7 @@ class Crypto
 
         $ret = [
             'PEM' => $data,
-            'password' => $metadata->getString($prefix . 'privatekey_pass', null),
+            'password' => $metadata->getOptionalString($prefix . 'privatekey_pass', null),
         ];
 
         return $ret;
diff --git a/lib/SimpleSAML/Utils/EMail.php b/lib/SimpleSAML/Utils/EMail.php
index 8a99fe0de908ad7da546db779a2c9b51f343e344..edd75d8f30eea1b3279a7750e31bfd0b73312fb5 100644
--- a/lib/SimpleSAML/Utils/EMail.php
+++ b/lib/SimpleSAML/Utils/EMail.php
@@ -65,7 +65,7 @@ class EMail
     public function getDefaultMailAddress(): string
     {
         $config = Configuration::getInstance();
-        $address = $config->getString('technicalcontact_email', 'na@example.org');
+        $address = $config->getOptionalString('technicalcontact_email', 'na@example.org');
         $address = preg_replace('/^mailto:/i', '', $address);
         if ('na@example.org' === $address) {
             throw new \Exception('technicalcontact_email must be changed from the default value');
@@ -228,7 +228,7 @@ class EMail
     {
         $config = Configuration::getInstance();
         $EMail->setTransportMethod(
-            $config->getString('mail.transport.method', 'mail'),
+            $config->getOptionalString('mail.transport.method', 'mail'),
             $config->getArrayize('mail.transport.options', [])
         );
 
diff --git a/lib/SimpleSAML/Utils/HTTP.php b/lib/SimpleSAML/Utils/HTTP.php
index 6482e68e6d32b0bfcb192bdf44a5e7d48f1aba05..3e9d0585076bd5c2ac2184aff6da7b4ec2744c7b 100644
--- a/lib/SimpleSAML/Utils/HTTP.php
+++ b/lib/SimpleSAML/Utils/HTTP.php
@@ -406,10 +406,10 @@ class HTTP
 
             $self_host = $this->getSelfHostWithNonStandardPort();
 
-            $trustedRegex = Configuration::getInstance()->getValue('trusted.url.regex', false);
+            $trustedRegex = Configuration::getInstance()->getOptionalString('trusted.url.regex', null);
 
             $trusted = false;
-            if ($trustedRegex) {
+            if ($trustedRegex !== null) {
                 // add self host to the white list
                 $trustedSites[] = preg_quote($self_host);
                 foreach ($trustedSites as $regex) {
@@ -455,13 +455,13 @@ class HTTP
     {
         $config = Configuration::getInstance();
 
-        $proxy = $config->getString('proxy', null);
+        $proxy = $config->getOptionalString('proxy', null);
         if ($proxy !== null) {
             if (!isset($context['http']['proxy'])) {
                 $context['http']['proxy'] = $proxy;
             }
-            $proxy_auth = $config->getString('proxy.auth', false);
-            if ($proxy_auth !== false) {
+            $proxy_auth = $config->getOptionalString('proxy.auth', null);
+            if ($proxy_auth !== null) {
                 $context['http']['header'] = "Proxy-Authorization: Basic " . base64_encode($proxy_auth);
             }
             if (!isset($context['http']['request_fulluri'])) {
@@ -638,7 +638,7 @@ class HTTP
     public function getBaseURL(): string
     {
         $globalConfig = Configuration::getInstance();
-        $baseURL = $globalConfig->getString('baseurlpath', 'simplesaml/');
+        $baseURL = $globalConfig->getOptionalString('baseurlpath', 'simplesaml/');
 
         if (preg_match('#^https?://.*/?$#D', $baseURL, $matches)) {
             // full URL in baseurlpath, override local server values
@@ -805,7 +805,7 @@ class HTTP
 
             /** @var \SimpleSAML\Configuration $appcfg */
             $appcfg = $cfg->getConfigItem('application');
-            $appurl = $appcfg->getString('baseURL', '');
+            $appurl = $appcfg->getOptionalString('baseURL', null);
             if (!empty($appurl)) {
                 $protocol = parse_url($appurl, PHP_URL_SCHEME);
                 $hostname = parse_url($appurl, PHP_URL_HOST);
diff --git a/lib/SimpleSAML/Utils/System.php b/lib/SimpleSAML/Utils/System.php
index 33efcae4e170c20a3f3aa0fab6380c0470998972..e2dde4be3c3a5a42c1ef147aa2c50293d50e1993 100644
--- a/lib/SimpleSAML/Utils/System.php
+++ b/lib/SimpleSAML/Utils/System.php
@@ -75,7 +75,7 @@ class System
         $globalConfig = Configuration::getInstance();
 
         $tempDir = rtrim(
-            $globalConfig->getString(
+            $globalConfig->getOptionalString(
                 'tempdir',
                 sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'simplesaml'
             ),
diff --git a/lib/SimpleSAML/Utils/Time.php b/lib/SimpleSAML/Utils/Time.php
index b152edb05b8c724acf8f61cbed2210543433a75a..f0e37c2b40e9036895be94cdf6f78ba392fd3a63 100644
--- a/lib/SimpleSAML/Utils/Time.php
+++ b/lib/SimpleSAML/Utils/Time.php
@@ -56,7 +56,7 @@ class Time
 
         $globalConfig = Configuration::getInstance();
 
-        $timezone = $globalConfig->getString('timezone', null);
+        $timezone = $globalConfig->getOptionalString('timezone', null);
         if ($timezone !== null) {
             if (!date_default_timezone_set($timezone)) {
                 throw new Error\Exception('Invalid timezone set in the "timezone" option in config.php.');
diff --git a/lib/SimpleSAML/XHTML/IdPDisco.php b/lib/SimpleSAML/XHTML/IdPDisco.php
index 8a6275c68733136e2c98bc69cfbcd62af840df68..852a2d6de6f0afb7420047c01fbcc8dbce1c5dc2 100644
--- a/lib/SimpleSAML/XHTML/IdPDisco.php
+++ b/lib/SimpleSAML/XHTML/IdPDisco.php
@@ -513,7 +513,7 @@ class IdPDisco
         $httpUtils = new Utils\HTTP();
         $idp = $this->getTargetIdP();
         if ($idp !== null) {
-            $extDiscoveryStorage = $this->config->getString('idpdisco.extDiscoveryStorage', null);
+            $extDiscoveryStorage = $this->config->getOptionalString('idpdisco.extDiscoveryStorage', null);
             if ($extDiscoveryStorage !== null) {
                 $this->log('Choice made [' . $idp . '] (Forwarding to external discovery storage)');
                 $httpUtils->redirectTrustedURL($extDiscoveryStorage, [
@@ -576,7 +576,7 @@ class IdPDisco
          * Make use of an XHTML template to present the select IdP choice to the user. Currently the supported options
          * is either a drop down menu or a list view.
          */
-        switch ($this->config->getString('idpdisco.layout', 'links')) {
+        switch ($this->config->getOptionalString('idpdisco.layout', 'links')) {
             case 'dropdown':
                 $templateFile = 'selectidp-dropdown.twig';
                 break;
diff --git a/lib/SimpleSAML/XHTML/Template.php b/lib/SimpleSAML/XHTML/Template.php
index da2b9dbf83bdf1daa6e509fe5dd478000f91c93d..8b0c421aeea76ac00ea28c2859312987cf8b6c68 100644
--- a/lib/SimpleSAML/XHTML/Template.php
+++ b/lib/SimpleSAML/XHTML/Template.php
@@ -129,7 +129,7 @@ class Template extends Response
 
         // parse config to find theme and module theme is in, if any
         list($this->theme['module'], $this->theme['name']) = $this->findModuleAndTemplateName(
-            $this->configuration->getString('theme.use', 'default')
+            $this->configuration->getOptionalString('theme.use', 'default')
         );
 
         // initialize internationalization system
@@ -137,9 +137,9 @@ class Template extends Response
         $this->localization = new Localization($configuration);
 
         // check if we need to attach a theme controller
-        $controller = $this->configuration->getString('theme.controller', false);
+        $controller = $this->configuration->getOptionalString('theme.controller', null);
         if (
-            $controller
+            $controller !== null
             && class_exists($controller)
             && in_array(TemplateControllerInterface::class, class_implements($controller))
         ) {
@@ -266,7 +266,7 @@ class Template extends Response
     private function setupTwig(): Environment
     {
         $auto_reload = $this->configuration->getOptionalBoolean('template.auto_reload', true);
-        $cache = $this->configuration->getString('template.cache', false);
+        $cache = $this->configuration->getOptionalString('template.cache', null);
 
         // set up template paths
         $loader = $this->setupTwigTemplatepaths();
@@ -287,7 +287,7 @@ class Template extends Response
         // set up translation
         $options = [
             'auto_reload' => $auto_reload,
-            'cache' => $cache,
+            'cache' => $cache ?? false,
             'strict_variables' => true,
         ];
 
@@ -299,7 +299,7 @@ class Template extends Response
         $twig->addFunction(new TwigFunction('moduleURL', [Module::class, 'getModuleURL']));
 
         // initialize some basic context
-        $langParam = $this->configuration->getString('language.parameter.name', 'language');
+        $langParam = $this->configuration->getOptionalString('language.parameter.name', 'language');
         $twig->addGlobal('languageParameterName', $langParam);
         $twig->addGlobal('currentLanguage', $this->translator->getLanguage()->getLanguage());
         $twig->addGlobal('isRTL', false); // language RTL configuration
@@ -488,7 +488,7 @@ class Template extends Response
 
         $this->data['year'] = date('Y');
 
-        $this->data['header'] = $this->configuration->getValue('theme.header', 'SimpleSAMLphp');
+        $this->data['header'] = $this->configuration->getOptionalString('theme.header', 'SimpleSAMLphp');
     }
 
     /**
diff --git a/modules/admin/lib/Controller/Config.php b/modules/admin/lib/Controller/Config.php
index b149465d8b51835f1ba93ce18dd0d11b931ed2f7..1a70d345e64211535e097e2879929d6100a88164 100644
--- a/modules/admin/lib/Controller/Config.php
+++ b/modules/admin/lib/Controller/Config.php
@@ -202,7 +202,7 @@ class Config
                 'enabled' => version_compare(phpversion(), '7.4', '>=')
             ]
         ];
-        $store = $this->config->getString('store.type', '');
+        $store = $this->config->getOptionalString('store.type', null);
 
         // check dependencies used via normal functions
         $functions = [
@@ -354,13 +354,13 @@ class Config
         $matrix[] = [
             'required' => 'optional',
             'descr' => Translate::noop('The <code>technicalcontact_email</code> configuration option should be set'),
-            'enabled' => $this->config->getString('technicalcontact_email', 'na@example.org') !== 'na@example.org',
+            'enabled' => $this->config->getOptionalString('technicalcontact_email', 'na@example.org') !== 'na@example.org',
         ];
 
         $matrix[] = [
             'required' => 'required',
             'descr' => Translate::noop('The auth.adminpassword configuration option must be set'),
-            'enabled' => $this->config->getString('auth.adminpassword', '123') !== '123',
+            'enabled' => $this->config->getOptionalString('auth.adminpassword', '123') !== '123',
         ];
 
         $cryptoUtils = new Utils\Crypto();
@@ -468,7 +468,7 @@ class Config
                     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                     curl_setopt($ch, CURLOPT_USERAGENT, 'SimpleSAMLphp');
                     curl_setopt($ch, CURLOPT_TIMEOUT, 2);
-                    curl_setopt($ch, CURLOPT_PROXY, $this->config->getString('proxy', null));
+                    curl_setopt($ch, CURLOPT_PROXY, $this->config->getOptionalString('proxy', null));
                     curl_setopt($ch, CURLOPT_PROXYUSERPWD, $this->config->getValue('proxy.auth', null));
                     $response = curl_exec($ch);
 
diff --git a/modules/core/hooks/hook_sanitycheck.php b/modules/core/hooks/hook_sanitycheck.php
index 53c0d9e8219c9874f7dbe3f68ee26f6bcefba2b8..09befb775d91d00371986930bf23c730dcf3c898 100644
--- a/modules/core/hooks/hook_sanitycheck.php
+++ b/modules/core/hooks/hook_sanitycheck.php
@@ -18,13 +18,13 @@ function core_hook_sanitycheck(array &$hookinfo): void
 
     $config = Configuration::getInstance();
 
-    if ($config->getString('auth.adminpassword', '123') === '123') {
+    if ($config->getOptionalString('auth.adminpassword', '123') === '123') {
         $hookinfo['errors'][] = '[core] Password in config.php is not set properly';
     } else {
         $hookinfo['info'][] = '[core] Password in config.php is set properly';
     }
 
-    if ($config->getString('technicalcontact_email', 'na@example.org') === 'na@example.org') {
+    if ($config->getOptionalString('technicalcontact_email', 'na@example.org') === 'na@example.org') {
         $hookinfo['errors'][] = '[core] In config.php technicalcontact_email is not set properly';
     } else {
         $hookinfo['info'][] = '[core] In config.php technicalcontact_email is set properly';
diff --git a/modules/core/lib/Auth/Source/AdminPassword.php b/modules/core/lib/Auth/Source/AdminPassword.php
index 0af50a1ed782534d5c814bada7e7c90311135a59..467a798f10fc74dced06d7a11c0d2a5ea5922d94 100644
--- a/modules/core/lib/Auth/Source/AdminPassword.php
+++ b/modules/core/lib/Auth/Source/AdminPassword.php
@@ -50,7 +50,7 @@ class AdminPassword extends UserPassBase
     protected function login(string $username, string $password): array
     {
         $config = Configuration::getInstance();
-        $adminPassword = $config->getString('auth.adminpassword', '123');
+        $adminPassword = $config->getOptionalString('auth.adminpassword', '123');
         if ($adminPassword === '123') {
             // We require that the user changes the password
             throw new Error\Error('NOTSET');
diff --git a/modules/core/lib/Stats/Output/Log.php b/modules/core/lib/Stats/Output/Log.php
index 58c554b574c555616847965b98b59545b5402ec7..86d740270e804d6c266ec17d432dc9c78e0a974d 100644
--- a/modules/core/lib/Stats/Output/Log.php
+++ b/modules/core/lib/Stats/Output/Log.php
@@ -29,7 +29,7 @@ class Log extends \SimpleSAML\Stats\Output
      */
     public function __construct(Configuration $config)
     {
-        $logLevel = $config->getString('level', 'notice');
+        $logLevel = $config->getOptionalString('level', 'notice');
         $this->logger = [Logger::class, $logLevel];
         if (!is_callable($this->logger)) {
             throw new \Exception('Invalid log level: ' . var_export($logLevel, true));
diff --git a/modules/multiauth/lib/Auth/Source/MultiAuth.php b/modules/multiauth/lib/Auth/Source/MultiAuth.php
index 922c6381f2f242deaab8ca845cc266bbf22ddcfa..9b974105e59009dce4ef49ca5f6892c8fc704dc9 100644
--- a/modules/multiauth/lib/Auth/Source/MultiAuth.php
+++ b/modules/multiauth/lib/Auth/Source/MultiAuth.php
@@ -80,7 +80,7 @@ class MultiAuth extends Auth\Source
         }
 
         $globalConfiguration = Configuration::getInstance();
-        $defaultLanguage = $globalConfiguration->getString('language.default', 'en');
+        $defaultLanguage = $globalConfiguration->getOptionalString('language.default', 'en');
         $authsources = Configuration::getConfig('authsources.php');
         $this->sources = [];
 
diff --git a/modules/multiauth/lib/Controller/DiscoController.php b/modules/multiauth/lib/Controller/DiscoController.php
index 09f577e9fc99acdb7cd132d183901eff8a0d27ca..57591e81ae9b316382a4d77522ca992b953df6ed 100644
--- a/modules/multiauth/lib/Controller/DiscoController.php
+++ b/modules/multiauth/lib/Controller/DiscoController.php
@@ -129,7 +129,7 @@ class DiscoController
 
         $t = new Template($this->config, 'multiauth:selectsource.twig');
 
-        $defaultLanguage = $this->config->getString('language.default', 'en');
+        $defaultLanguage = $this->config->getOptionalString('language.default', 'en');
         $language = $t->getTranslator()->getLanguage()->getLanguage();
 
         $sources = $state[MultiAuth::SOURCESID];
diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php
index 4b886db7ac4d35154917cce61bace0d0180735d3..81ef882deac31f6b0d44c30c0ce2a9774d40404a 100644
--- a/modules/saml/lib/Auth/Source/SP.php
+++ b/modules/saml/lib/Auth/Source/SP.php
@@ -94,8 +94,8 @@ class SP extends \SimpleSAML\Auth\Source
             'authsources[' . var_export($this->authId, true) . ']'
         );
         $this->entityId = $this->metadata->getString('entityID');
-        $this->idp = $this->metadata->getString('idp', null);
-        $this->discoURL = $this->metadata->getString('discoURL', null);
+        $this->idp = $this->metadata->getOptionalString('idp', null);
+        $this->discoURL = $this->metadata->getOptionalString('discoURL', null);
         $this->disable_scoping = $this->metadata->getOptionalBoolean('disable_scoping', false);
     }
 
@@ -141,7 +141,7 @@ class SP extends \SimpleSAML\Auth\Source
         if ($this->metadata->hasValue('NameIDPolicy')) {
             $format = $this->metadata->getValue('NameIDPolicy');
             if (is_array($format)) {
-                $metadata['NameIDFormat'] = Configuration::loadFromArray($format)->getString(
+                $metadata['NameIDFormat'] = Configuration::loadFromArray($format)->getOptionalString(
                     'Format',
                     Constants::NAMEID_TRANSIENT
                 );
@@ -196,11 +196,11 @@ class SP extends \SimpleSAML\Auth\Source
 
         // add technical contact
         $globalConfig = Configuration::getInstance();
-        $email = $globalConfig->getString('technicalcontact_email', 'na@example.org');
-        if ($email && $email !== 'na@example.org') {
+        $email = $globalConfig->getOptionalString('technicalcontact_email', 'na@example.org');
+        if (!empty($email) && $email !== 'na@example.org') {
             $contact = [
                 'emailAddress' => $email,
-                'givenName' => $globalConfig->getString('technicalcontact_name', null),
+                'givenName' => $globalConfig->getOptionalString('technicalcontact_name', null),
                 'contactType' => 'technical',
             ];
             $metadata['contacts'][] = Utils\Config\Metadata::getContact($contact);
@@ -339,7 +339,7 @@ class SP extends \SimpleSAML\Auth\Source
             Constants::BINDING_HTTP_POST,
             Constants::BINDING_HTTP_ARTIFACT,
         ];
-        if ($this->metadata->getString('ProtocolBinding', '') === Constants::BINDING_HOK_SSO) {
+        if ($this->metadata->getOptionalString('ProtocolBinding', null) === Constants::BINDING_HOK_SSO) {
             $default[] = Constants::BINDING_HOK_SSO;
         }
 
@@ -387,7 +387,7 @@ class SP extends \SimpleSAML\Auth\Source
     private function getSLOEndpoints(): array
     {
         $config = Configuration::getInstance();
-        $storeType = $config->getString('store.type', 'phpsession');
+        $storeType = $config->getOptionalString('store.type', 'phpsession');
 
         $store = StoreFactory::getInstance($storeType);
         $bindings = $this->metadata->getOptionalArray(
@@ -398,7 +398,7 @@ class SP extends \SimpleSAML\Auth\Source
             ]
         );
         $defaultLocation = Module::getModuleURL('saml/sp/saml2-logout.php/' . $this->getAuthId());
-        $location = $this->metadata->getString('SingleLogoutServiceLocation', $defaultLocation);
+        $location = $this->metadata->getOptionalString('SingleLogoutServiceLocation', $defaultLocation);
 
         $endpoints = [];
         foreach ($bindings as $binding) {
@@ -441,7 +441,7 @@ class SP extends \SimpleSAML\Auth\Source
         $arrayUtils = new Utils\Arrays();
 
         $accr = null;
-        if ($idpMetadata->getString('AuthnContextClassRef', false)) {
+        if ($idpMetadata->getOptionalString('AuthnContextClassRef', null) !== null) {
             $accr = $arrayUtils->arrayize($idpMetadata->getString('AuthnContextClassRef'));
         } elseif (isset($state['saml:AuthnContextClassRef'])) {
             $accr = $arrayUtils->arrayize($state['saml:AuthnContextClassRef']);
@@ -449,7 +449,7 @@ class SP extends \SimpleSAML\Auth\Source
 
         if ($accr !== null) {
             $comp = Constants::COMPARISON_EXACT;
-            if ($idpMetadata->getString('AuthnContextComparison', false)) {
+            if ($idpMetadata->getOptionalString('AuthnContextComparison', null) !== null) {
                 $comp = $idpMetadata->getString('AuthnContextComparison');
             } elseif (
                 isset($state['saml:AuthnContextComparison'])
@@ -577,7 +577,7 @@ class SP extends \SimpleSAML\Auth\Source
             $ar->setExtensions($this->metadata->getArray('saml:Extensions'));
         }
 
-        $providerName = $this->metadata->getString("ProviderName", null);
+        $providerName = $this->metadata->getOptionalString("ProviderName", null);
         if ($providerName !== null) {
             $ar->setProviderName($providerName);
         }
@@ -1141,7 +1141,7 @@ class SP extends \SimpleSAML\Auth\Source
             if (!empty($state['saml:sp:RelayState'])) {
                 $redirectTo = $state['saml:sp:RelayState'];
             } else {
-                $redirectTo = $source->getMetadata()->getString('RelayState', '/');
+                $redirectTo = $source->getMetadata()->getOptionalString('RelayState', '/');
             }
 
             self::handleUnsolicitedAuth($sourceId, $state, $redirectTo);
diff --git a/modules/saml/lib/IdP/SAML2.php b/modules/saml/lib/IdP/SAML2.php
index 4592d2059ba023f83e2c806a1b68640d50b4f94f..733c0b113c166b0086e1719693070fc6a1143ae0 100644
--- a/modules/saml/lib/IdP/SAML2.php
+++ b/modules/saml/lib/IdP/SAML2.php
@@ -662,7 +662,7 @@ class SAML2
                 'idpEntityID' => $idpMetadata->getString('entityid'),
             ]);
 
-            $spStatsId = $spMetadata->getString('core:statistics-id', $spEntityId);
+            $spStatsId = $spMetadata->getOptionalString('core:statistics-id', $spEntityId);
             Logger::stats('saml20-idp-SLO spinit ' . $spStatsId . ' ' . $idpMetadata->getString('entityid'));
 
             $state = [
@@ -937,11 +937,11 @@ class SAML2
         }
 
         $globalConfig = Configuration::getInstance();
-        $email = $globalConfig->getString('technicalcontact_email', false);
-        if ($email && $email !== 'na@example.org') {
+        $email = $globalConfig->getOptionalString('technicalcontact_email', 'na@example.org');
+        if (!empty($email) && $email !== 'na@example.org') {
             $contact = [
                 'emailAddress' => $email,
-                'givenName' => $globalConfig->getString('technicalcontact_name', null),
+                'givenName' => $globalConfig->getOptionalString('technicalcontact_name', null),
                 'contactType' => 'technical',
             ];
             $metadata['contacts'][] = Utils\Config\Metadata::getContact($contact);
@@ -965,9 +965,9 @@ class SAML2
         Configuration $spMetadata,
         array &$state
     ): ?string {
-        $attribute = $spMetadata->getString('simplesaml.nameidattribute', null);
+        $attribute = $spMetadata->getOptionalString('simplesaml.nameidattribute', null);
         if ($attribute === null) {
-            $attribute = $idpMetadata->getString('simplesaml.nameidattribute', null);
+            $attribute = $idpMetadata->getOptionalString('simplesaml.nameidattribute', null);
             if ($attribute === null) {
                 Logger::error('Unable to generate NameID. Check the simplesaml.nameidattribute option.');
                 return null;
@@ -1083,21 +1083,21 @@ class SAML2
         Configuration $spMetadata
     ): string {
         // try SP metadata first
-        $attributeNameFormat = $spMetadata->getString('attributes.NameFormat', null);
+        $attributeNameFormat = $spMetadata->getOptionalString('attributes.NameFormat', null);
         if ($attributeNameFormat !== null) {
             return $attributeNameFormat;
         }
-        $attributeNameFormat = $spMetadata->getString('AttributeNameFormat', null);
+        $attributeNameFormat = $spMetadata->getOptionalString('AttributeNameFormat', null);
         if ($attributeNameFormat !== null) {
             return $attributeNameFormat;
         }
 
         // look in IdP metadata
-        $attributeNameFormat = $idpMetadata->getString('attributes.NameFormat', null);
+        $attributeNameFormat = $idpMetadata->getOptionalString('attributes.NameFormat', null);
         if ($attributeNameFormat !== null) {
             return $attributeNameFormat;
         }
-        $attributeNameFormat = $idpMetadata->getString('AttributeNameFormat', null);
+        $attributeNameFormat = $idpMetadata->getOptionalString('AttributeNameFormat', null);
         if ($attributeNameFormat !== null) {
             return $attributeNameFormat;
         }
@@ -1264,7 +1264,7 @@ class SAML2
             $nameId = $state['saml:NameID'][$nameIdFormat];
             $nameId->setFormat($nameIdFormat);
         } else {
-            $spNameQualifier = $spMetadata->getString('SPNameQualifier', null);
+            $spNameQualifier = $spMetadata->getOptionalString('SPNameQualifier', null);
             if ($spNameQualifier === null) {
                 $spNameQualifier = $spMetadata->getString('entityid');
             }
@@ -1334,12 +1334,12 @@ class SAML2
         }
 
 
-        $sharedKey = $spMetadata->getString('sharedkey', null);
+        $sharedKey = $spMetadata->getOptionalString('sharedkey', null);
         if ($sharedKey !== null) {
-            $algo = $spMetadata->getString('sharedkey_algorithm', null);
+            $algo = $spMetadata->getOptionalString('sharedkey_algorithm', null);
             if ($algo === null) {
                 // If no algorithm is configured, use a sane default
-                $algo = $idpMetadata->getString('sharedkey_algorithm', XMLSecurityKey::AES128_GCM);
+                $algo = $idpMetadata->getOptionalString('sharedkey_algorithm', XMLSecurityKey::AES128_GCM);
             }
 
             $key = new XMLSecurityKey($algo);
diff --git a/modules/saml/lib/IdP/SQLNameID.php b/modules/saml/lib/IdP/SQLNameID.php
index b0dda950c285e032be7d928d63e59545f1b5ef33..24e2e0f85c49d2c15865f3e67955bc911666ed0c 100644
--- a/modules/saml/lib/IdP/SQLNameID.php
+++ b/modules/saml/lib/IdP/SQLNameID.php
@@ -159,7 +159,7 @@ class SQLNameID
     private static function getStore(): Store\SQLStore
     {
         $config = Configuration::getInstance();
-        $storeType = $config->getString('store.type', 'phpsession');
+        $storeType = $config->getOptionalString('store.type', 'phpsession');
 
         $store = StoreFactory::getInstance($storeType);
         Assert::isInstanceOf(
diff --git a/modules/saml/lib/Message.php b/modules/saml/lib/Message.php
index fc2831bf3125ca154a816e34fc9d0d097ed2bb58..ade1618629214852a94632c6b14186775bad21f5 100644
--- a/modules/saml/lib/Message.php
+++ b/modules/saml/lib/Message.php
@@ -43,7 +43,7 @@ class Message
         Configuration $dstMetadata,
         SignedElement $element
     ): void {
-        $dstPrivateKey = $dstMetadata->getString('signature.privatekey', null);
+        $dstPrivateKey = $dstMetadata->getOptionalString('signature.privatekey', null);
         $cryptoUtils = new Utils\Crypto();
 
         if ($dstPrivateKey !== null) {
@@ -56,9 +56,9 @@ class Message
             $certArray = $cryptoUtils->loadPublicKey($srcMetadata, false);
         }
 
-        $algo = $dstMetadata->getString('signature.algorithm', null);
+        $algo = $dstMetadata->getOptionalString('signature.algorithm', null);
         if ($algo === null) {
-            $algo = $srcMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA256);
+            $algo = $srcMetadata->getOptionalString('signature.algorithm', XMLSecurityKey::RSA_SHA256);
         }
 
         $privateKey = new XMLSecurityKey($algo, ['type' => 'private']);
@@ -254,15 +254,15 @@ class Message
         Configuration $dstMetadata,
         $encryptionMethod = null
     ): array {
-        $sharedKey = $srcMetadata->getString('sharedkey', null);
+        $sharedKey = $srcMetadata->getOptionalString('sharedkey', null);
         if ($sharedKey !== null) {
             if ($encryptionMethod !== null) {
                 $algo = $encryptionMethod->getAlgorithm();
             } else {
-                $algo = $srcMetadata->getString('sharedkey_algorithm', null);
+                $algo = $srcMetadata->getOptionalString('sharedkey_algorithm', null);
                 if ($algo === null) {
                     // If no algorithm is supplied or configured, use a sane default as a last resort
-                    $algo = $dstMetadata->getString('sharedkey_algorithm', XMLSecurityKey::AES128_GCM);
+                    $algo = $dstMetadata->getOptionalString('sharedkey_algorithm', XMLSecurityKey::AES128_GCM);
                 }
             }
 
@@ -880,7 +880,7 @@ class Message
      */
     public static function getEncryptionKey(Configuration $metadata): XMLSecurityKey
     {
-        $sharedKey = $metadata->getString('sharedkey', null);
+        $sharedKey = $metadata->getOptionalString('sharedkey', null);
         if ($sharedKey !== null) {
             $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
             $key->loadKey($sharedKey);
diff --git a/modules/saml/lib/SP/LogoutStore.php b/modules/saml/lib/SP/LogoutStore.php
index 6911e0eb70b452dafc8fd48c1c592e50408cce50..09f46cc1fc73231c9466e7da566870e79564f4e0 100644
--- a/modules/saml/lib/SP/LogoutStore.php
+++ b/modules/saml/lib/SP/LogoutStore.php
@@ -214,7 +214,7 @@ class LogoutStore
         }
 
         $config = Configuration::getInstance();
-        $storeType = $config->getString('store.type', 'phpsession');
+        $storeType = $config->getOptionalString('store.type', 'phpsession');
 
         $store = StoreFactory::getInstance($storeType);
         if ($store === false) {
@@ -253,7 +253,7 @@ class LogoutStore
     public static function logoutSessions(string $authId, NameID $nameId, array $sessionIndexes)
     {
         $config = Configuration::getInstance();
-        $storeType = $config->getString('store.type', 'phpsession');
+        $storeType = $config->getOptionalString('store.type', 'phpsession');
 
         $store = StoreFactory::getInstance($storeType);
         if ($store === false) {
diff --git a/modules/saml/www/sp/metadata.php b/modules/saml/www/sp/metadata.php
index 454883978e1b7e57c984f7006a4f7e3ec5e1b2b7..4992710fbee9066de45a92f2ad0318876df0641b 100644
--- a/modules/saml/www/sp/metadata.php
+++ b/modules/saml/www/sp/metadata.php
@@ -34,7 +34,7 @@ $entityId = $source->getEntityId();
 $spconfig = $source->getMetadata();
 $metaArray20 = $source->getHostedMetadata();
 
-$storeType = $config->getString('store.type', 'phpsession');
+$storeType = $config->getOptionalString('store.type', 'phpsession');
 $store = StoreFactory::getInstance($storeType);
 
 $metaBuilder = new Metadata\SAMLBuilder($entityId);
diff --git a/modules/saml/www/sp/saml2-acs.php b/modules/saml/www/sp/saml2-acs.php
index 3da83aa49567b33b6132e80e5e222e61f68a53ce..fd670e8b5233b32e7a351a73cb6b420282748f42 100644
--- a/modules/saml/www/sp/saml2-acs.php
+++ b/modules/saml/www/sp/saml2-acs.php
@@ -128,7 +128,7 @@ if ($state) {
     }
 } else {
     // this is an unsolicited response
-    $relaystate = $spMetadata->getString('RelayState', $response->getRelayState());
+    $relaystate = $spMetadata->getOptionalString('RelayState', $response->getRelayState());
     $state = [
         'saml:sp:isUnsolicited' => true,
         'saml:sp:AuthId'        => $sourceId,
diff --git a/tests/lib/SimpleSAML/ConfigurationTest.php b/tests/lib/SimpleSAML/ConfigurationTest.php
index c77c650ffefee6be1ad95697101e1e33bcb385f1..38cdee13cb8cea0abfc5829b88e057c29a8ac277 100644
--- a/tests/lib/SimpleSAML/ConfigurationTest.php
+++ b/tests/lib/SimpleSAML/ConfigurationTest.php
@@ -308,33 +308,42 @@ class ConfigurationTest extends ClearStateTestCase
     {
         $c = Configuration::loadFromArray([
             'str_opt' => 'Hello World!',
+            'wrong_opt' => true,
         ]);
-        $this->assertEquals($c->getString('missing_opt', '--missing--'), '--missing--');
-        $this->assertEquals($c->getString('str_opt', '--missing--'), 'Hello World!');
-    }
 
+        // Normal use
+        $this->assertEquals($c->getString('str_opt'), 'Hello World!');
 
-    /**
-     * Test \SimpleSAML\Configuration::getString() missing option
-     */
-    public function testGetStringMissing(): void
-    {
-        $this->expectException(Exception::class);
-        $c = Configuration::loadFromArray([]);
+        // Missing option
+        $this->expectException(AssertionFailedException::class);
         $c->getString('missing_opt');
+
+        // Invalid option type
+        $this->expectException(AssertionFailedException::class);
+        $c->getString('wrong_opt');
     }
 
 
     /**
-     * Test \SimpleSAML\Configuration::getString() wrong option
+     * Test \SimpleSAML\Configuration::getOptionalString() missing option
      */
-    public function testGetStringWrong(): void
+    public function testGetOptionalString(): void
     {
-        $this->expectException(Exception::class);
         $c = Configuration::loadFromArray([
-            'wrong' => false,
+            'str_opt' => 'Hello World!',
+            'wrong_opt' => true,
         ]);
-        $c->getString('wrong');
+
+        // Normal use
+        $this->assertEquals($c->getOptionalString('str_opt', 'Hello World!'), 'Hello World!');
+        $this->assertEquals($c->getOptionalString('str_opt', 'something else'), 'Hello World!');
+
+        // Missing option
+        $this->assertEquals($c->getOptionalString('missing_opt', 'Hello World!'), 'Hello World!');
+
+        // Invalid option type
+        $this->expectException(AssertionFailedException::class);
+        $c->getOptionalString('wrong_opt', 'Hello World!');
     }
 
 
diff --git a/tests/lib/SimpleSAML/Store/StoreFactoryTest.php b/tests/lib/SimpleSAML/Store/StoreFactoryTest.php
index 3164d5f1c67dfe7cebaa00870f39fd53b16cd538..27a421916c813f64dd052bc7f3121d2ee977d41f 100644
--- a/tests/lib/SimpleSAML/Store/StoreFactoryTest.php
+++ b/tests/lib/SimpleSAML/Store/StoreFactoryTest.php
@@ -32,7 +32,7 @@ class StoreFactoryTest extends TestCase
         Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
 
         $config = Configuration::getInstance();
-        $storeType = $config->getString('store.type', 'phpsession');
+        $storeType = $config->getOptionalString('store.type', 'phpsession');
 
         /** @var false $store */
         $store = StoreFactory::getInstance($storeType);
@@ -66,7 +66,7 @@ class StoreFactoryTest extends TestCase
     public function memcacheStore(): void
     {
         Configuration::loadFromArray([
-            'store.type'                    => 'memcache',
+            'store.type' => 'memcache',
         ], '[ARRAY]', 'simplesaml');
 
         $config = Configuration::getInstance();
@@ -166,7 +166,7 @@ class StoreFactoryTest extends TestCase
     protected function tearDown(): void
     {
         $config = Configuration::getInstance();
-        $storeType = $config->getString('store.type', 'phpsession');
+        $storeType = $config->getOptionalString('store.type', 'phpsession');
 
         /** @var \SimpleSAML\Store\StoreInterface $store */
         $store = StoreFactory::getInstance($storeType);
diff --git a/tests/modules/saml/lib/IdP/SQLNameIDTest.php b/tests/modules/saml/lib/IdP/SQLNameIDTest.php
index e12629ae73eb48ea695a8242d5a5c1962139ee1d..91e8a2be5f0b992a537e41cc8588dc7d126ff9a1 100644
--- a/tests/modules/saml/lib/IdP/SQLNameIDTest.php
+++ b/tests/modules/saml/lib/IdP/SQLNameIDTest.php
@@ -86,15 +86,15 @@ class SQLNameIDTest extends TestCase
     {
         $config = [
             'database.dsn'         => 'sqlite::memory:',
-            'database.username'    => null,
-            'database.password'    => null,
+            'database.username'    => '',
+            'database.password'    => '',
             'database.prefix'      => 'phpunit_',
             'database.persistent'  => true,
             'database.secondaries' => [
                 [
                     'dsn'      => 'sqlite::memory:',
-                    'username' => null,
-                    'password' => null,
+                    'username' => '',
+                    'password' => '',
                 ],
             ],
         ];
diff --git a/www/saml2/idp/ArtifactResolutionService.php b/www/saml2/idp/ArtifactResolutionService.php
index 4532c72d805ad9b50e63850d7c266f8072d5250c..6ba0ea8b3a85e2d6428d4dd42c7de09172720d93 100644
--- a/www/saml2/idp/ArtifactResolutionService.php
+++ b/www/saml2/idp/ArtifactResolutionService.php
@@ -35,7 +35,7 @@ if (!$idpMetadata->getOptionalBoolean('saml20.sendartifact', false)) {
     throw new Error\Error('NOACCESS');
 }
 
-$storeType = $config->getString('store.type', 'phpsession');
+$storeType = $config->getOptionalString('store.type', 'phpsession');
 $store = StoreFactory::getInstance($storeType);
 if ($store === false) {
     throw new Exception('Unable to send artifact without a datastore configured.');