diff --git a/config-templates/config.php b/config-templates/config.php
index f6de5cba9ef599b0a417640d3dda6d748a74177b..ea110c29aa75c6fa92c3fb9af4f406dae8e03d77 100644
--- a/config-templates/config.php
+++ b/config-templates/config.php
@@ -861,6 +861,37 @@ $config = [
      */
     'production' => true,
 
+    /*
+     * Set this option to adjust basic caching directives sent by module.php.
+     *
+     * Defaults to ['public' => true, 'max_age' => 86400]
+     */
+    // 'module.php.cache' => ['public' => true, 'max_age' => 86400],
+
+    /*
+     * Set this option to adjust expiration timestamp sent by module.php.
+     * The value (in seconds) is added to current time.
+     * If set to null, the Expiration header is not sent at all.
+     *
+     * Defaults to 10 * 60 (ten minutes).
+     */
+    // 'module.php.expires' => 10 * 60,
+
+    /*
+     * Set this option to make module.php automatically send Etag.
+     *
+     * Defaults to false.
+     */
+    // 'module.php.etag' => false,
+
+    /*
+     * Set this option to adjust more caching directives sent by module.php,
+     * for example must-revalidate. The option takes an array
+     * where keys are the caching directive names and values are the corresponding values.
+     *
+     * Defaults to [] (empty array).
+     */
+    // 'module.php.directives' => [],
 
 
     /*********************
diff --git a/lib/SimpleSAML/Module.php b/lib/SimpleSAML/Module.php
index e0bf063a5c4f59b7da97ed64927f250333936786..25b3160eee0ea6f6d795b433e0c380ce9e3f45b4 100644
--- a/lib/SimpleSAML/Module.php
+++ b/lib/SimpleSAML/Module.php
@@ -265,11 +265,21 @@ class Module
         }
 
         $response = new BinaryFileResponse($path);
-        $response->setCache(['public' => true, 'max_age' => 86400]);
-        $response->setExpires(new \DateTime(gmdate('D, j M Y H:i:s \G\M\T', time() + 10 * 60)));
-        $response->setLastModified(new \DateTime(gmdate('D, j M Y H:i:s \G\M\T', filemtime($path))));
+        $cacheSettings = $config->getArray('module.php.cache', ['public' => true, 'max_age' => 86400]);
+        $response->setCache($cacheSettings);
+        $cacheExpiration = $config->getValue('module.php.expires', 10 * 60);
+        $expires = $cacheExpiration === null ? null : new \DateTime('@' . (time() + $cacheExpiration));
+        $response->setExpires($expires);
+        $cacheEtag = $config->getBoolean('module.php.etag', false);
+        if ($cacheEtag) {
+            $response->setAutoEtag();
+        }
+        $cacheDirectives = $config->getArray('module.php.directives', []);
+        foreach ($cacheDirectives as $directiveName => $directiveValue) {
+            $response->headers->addCacheControlDirective($directiveName, $directiveValue);
+        }
+        $response->isNotModified($request);
         $response->headers->set('Content-Type', $contentType);
-        $response->headers->set('Content-Length', sprintf('%u', filesize($path))); // force file size to an unsigned
         $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_INLINE);
         $response->prepare($request);
         return $response;