diff --git a/rollup.utils.js b/rollup.utils.js
index 5784bad1cbca700a3cb73a9e4f026a0ffb5374ef..f2a1f200dd2d5a7b1860393f899272a3abc2989e 100644
--- a/rollup.utils.js
+++ b/rollup.utils.js
@@ -1,7 +1,11 @@
 import path from 'path';
 import url from 'url';
+import fs from 'fs';
 import child_process from 'child_process';
 import resolve from '@rollup/plugin-node-resolve';
+import selfsigned from 'selfsigned';
+import findCacheDir from 'find-cache-dir';
+import { assert } from 'console';
 
 export function getBuildInfo(build) {
     let remote = child_process.execSync('git config --get remote.origin.url').toString().trim();
@@ -40,4 +44,27 @@ export async function getPackagePath(packageName, assetPath) {
         packageRoot = path.dirname(require.resolve(packageName + '/package.json'));
     }
     return path.relative(process.cwd(), path.join(packageRoot, assetPath));
+}
+
+/**
+ * Creates a dummy dev server certificate, caches it and returns it.
+ */
+export async function generateTLSConfig() {
+    const certDir = findCacheDir({name: 'dbp-dev-server-cert'});
+    const keyPath = path.join(certDir, 'server.key');
+    const certPath = path.join(certDir, 'server.cert');
+
+    await fs.promises.mkdir(certDir, {recursive: true});
+
+    if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {
+        const attrs = [{name: 'commonName', value: 'dbp-dev.localhost'}];
+        const pems = selfsigned.generate(attrs, {algorithm: 'sha256', days: 9999});
+        await fs.promises.writeFile(keyPath, pems.private);
+        await fs.promises.writeFile(certPath, pems.cert);
+    }
+
+    return {
+        key: await fs.promises.readFile(keyPath),
+        cert: await fs.promises.readFile(certPath)
+    }
 }
\ No newline at end of file
diff --git a/toolkit-showcase/package.json b/toolkit-showcase/package.json
index b908bcbb2f89c396d2d4c230c91adc54f4856234..ca175e3f8c20eb3b0bb419ea4131418cec58d6b8 100644
--- a/toolkit-showcase/package.json
+++ b/toolkit-showcase/package.json
@@ -25,6 +25,7 @@
     "chokidar": "^3.4.0",
     "eslint": "^7.3.1",
     "eslint-plugin-jsdoc": "^31.0.0",
+    "find-cache-dir": "^3.3.1",
     "glob": "^7.1.6",
     "i18next-scanner": "^3.0.0",
     "karma": "^6.0.0",
@@ -48,11 +49,11 @@
     "@dbp-toolkit/auth": "^0.1.0",
     "@dbp-toolkit/common": "^0.1.0",
     "@dbp-toolkit/file-handling": "^0.1.0",
+    "@dbp-toolkit/font-source-sans-pro": "^0.1.0",
     "@dbp-toolkit/language-select": "^0.1.0",
     "@dbp-toolkit/notification": "^0.1.0",
     "@dbp-toolkit/person-profile": "^0.1.0",
     "@dbp-toolkit/person-select": "^0.1.0",
-    "@dbp-toolkit/font-source-sans-pro": "^0.1.0",
     "@open-wc/scoped-elements": "^1.1.1",
     "fabric": "^4.2.0",
     "file-saver": "^2.0.2",
diff --git a/toolkit-showcase/rollup.config.js b/toolkit-showcase/rollup.config.js
index a805c51158da25f939c7c00f70dd7dbca9cf8697..09abdccaef534a720abf1de6b2a694bc73a0c85b 100644
--- a/toolkit-showcase/rollup.config.js
+++ b/toolkit-showcase/rollup.config.js
@@ -1,5 +1,4 @@
 import path from 'path';
-import fs from 'fs';
 import url from 'url';
 import glob from 'glob';
 import resolve from '@rollup/plugin-node-resolve';
@@ -16,7 +15,7 @@ import del from 'rollup-plugin-delete';
 import md from 'rollup-plugin-md';
 import emitEJS from 'rollup-plugin-emit-ejs'
 import babel from '@rollup/plugin-babel'
-import selfsigned from 'selfsigned';
+import {generateTLSConfig} from '../rollup.utils.js';
 
 // -------------------------------
 
@@ -95,25 +94,6 @@ switch (build) {
 
 let nextcloudFileURL = nextcloudBaseURL + '/apps/files/?dir=';
 
-/**
- * Creates a server certificate and caches it in the .cert directory
- */
-function generateTLSConfig() {
-  fs.mkdirSync('.cert', {recursive: true});
-
-  if (!fs.existsSync('.cert/server.key') || !fs.existsSync('.cert/server.cert')) {
-    const attrs = [{name: 'commonName', value: 'dbp-dev.localhost'}];
-    const pems = selfsigned.generate(attrs, {algorithm: 'sha256', days: 9999});
-    fs.writeFileSync('.cert/server.key', pems.private);
-    fs.writeFileSync('.cert/server.cert', pems.cert);
-  }
-
-  return {
-    key: fs.readFileSync('.cert/server.key'),
-    cert: fs.readFileSync('.cert/server.cert')
-  }
-}
-
 function getBuildInfo() {
     const child_process = require('child_process');
     const url = require('url');
@@ -323,7 +303,7 @@ Dependencies:
           host: '127.0.0.1',
           port: 8001,
           historyApiFallback: basePath + pkg.name + '.html',
-          https: USE_HTTPS ? generateTLSConfig() : false,
+          https: USE_HTTPS ? await generateTLSConfig() : false,
           headers: {
               'Content-Security-Policy': `default-src 'self' 'unsafe-eval' 'unsafe-inline' analytics.tugraz.at ${keyCloakServer} ${entryPointURL} httpbin.org ${nextcloudBaseURL} www.handy-signatur.at ${pdfAsQualifiedlySigningServer} ; img-src * blob: data:`
           },
diff --git a/toolkit-showcase/yarn.lock b/toolkit-showcase/yarn.lock
index 61c01a5bc43485785a3f19f89e1888b776425199..1c5f5b1bd9c39db084724be3aa7015ec4582d8df 100644
--- a/toolkit-showcase/yarn.lock
+++ b/toolkit-showcase/yarn.lock
@@ -922,7 +922,7 @@
   resolved "https://registry.yarnpkg.com/@open-wc/dedupe-mixin/-/dedupe-mixin-1.3.0.tgz#0df5d438285fc3482838786ee81895318f0ff778"
   integrity sha512-UfdK1MPnR6T7f3svzzYBfu3qBkkZ/KsPhcpc3JYhsUY4hbpwNF9wEQtD4Z+/mRqMTJrKg++YSxIxE0FBhY3RIw==
 
-"@open-wc/scoped-elements@^1.1.1":
+"@open-wc/scoped-elements@^1.1.1", "@open-wc/scoped-elements@^1.3.3":
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/@open-wc/scoped-elements/-/scoped-elements-1.3.3.tgz#fe008aef4d74fb00c553c900602960638fc1c7b0"
   integrity sha512-vFIQVYYjFw67odUE4JzZOpctnF7S/2DX+S+clrL3bQPql7HvEnV0wMFwOWUavQTuCJi0rfU8GTcNMiUybio+Yg==