diff --git a/pass/app.js b/pass/app.js
index 0778cfb5fe32186aa5a1cec2ff8decd763d8e2b8..a09a9c36c3ac1d0510997aa565b91166a67320aa 100644
--- a/pass/app.js
+++ b/pass/app.js
@@ -28,11 +28,21 @@ app.use(express.urlencoded({ extended: false, limit: "1mb" }));
 app.use(cookieParser());
 
 app.use((req, res, next) => {
+  res.locals.baseDir = "";
   let subPath = req.url.match(/^((\/.*)?\/keys)/);
-  if (subPath) {
-    res.locals.baseDir = subPath[1];
-  } else {
-    res.locals.baseDir = "";
+  let allowed_hosts = [
+    "localhost",
+    "metager.de",
+    "metager.org"
+  ];
+  if (subPath && "x-forwarded-proto" in req.headers && "x-forwarded-host" in req.headers && "x-forwarded-port" in req.headers) {
+    if (allowed_hosts.includes(req.hostname) || (process.env.NODE_ENV === "development" && req.hostname.match(/^(localhost|.*\.ngrok\.io|.*\.review\.metager\.de)$/))) {
+      res.locals.baseDir = req.headers["x-forwarded-proto"] + "://" + req.headers["x-forwarded-host"];
+      if (!["80", "443"].includes(req.headers["x-forwarded-port"])) {
+        res.locals.baseDir += ":" + req.headers["x-forwarded-port"];
+      }
+      res.locals.baseDir += subPath[1];
+    }
   }
   next();
 });
diff --git a/pass/package-lock.json b/pass/package-lock.json
index 19c20264624beec1ead705e6c81327ba1ae51b51..5688512068209bb09a9c1a20bbc492a1eb8f1ece 100644
--- a/pass/package-lock.json
+++ b/pass/package-lock.json
@@ -30,6 +30,7 @@
         "multer": "^1.4.5-lts.1",
         "node-forge": "^1.3.1",
         "pdfkit": "^0.13.0",
+        "qr-scanner": "^1.4.2",
         "qrcode": "^1.5.1",
         "qrcode-reader": "^1.0.4",
         "uuid": "^9.0.0"
@@ -588,6 +589,11 @@
       "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
       "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
     },
+    "node_modules/@types/offscreencanvas": {
+      "version": "2019.7.0",
+      "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
+      "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
+    },
     "node_modules/@types/responselike": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
@@ -5086,6 +5092,14 @@
       "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
       "optional": true
     },
+    "node_modules/qr-scanner": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/qr-scanner/-/qr-scanner-1.4.2.tgz",
+      "integrity": "sha512-kV1yQUe2FENvn59tMZW6mOVfpq9mGxGf8l6+EGaXUOd4RBOLg7tRC83OrirM5AtDvZRpdjdlXURsHreAOSPOUw==",
+      "dependencies": {
+        "@types/offscreencanvas": "^2019.6.4"
+      }
+    },
     "node_modules/qrcode": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz",
@@ -7010,6 +7024,11 @@
       "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
       "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
     },
+    "@types/offscreencanvas": {
+      "version": "2019.7.0",
+      "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
+      "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
+    },
     "@types/responselike": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
@@ -10551,6 +10570,14 @@
       "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
       "optional": true
     },
+    "qr-scanner": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/qr-scanner/-/qr-scanner-1.4.2.tgz",
+      "integrity": "sha512-kV1yQUe2FENvn59tMZW6mOVfpq9mGxGf8l6+EGaXUOd4RBOLg7tRC83OrirM5AtDvZRpdjdlXURsHreAOSPOUw==",
+      "requires": {
+        "@types/offscreencanvas": "^2019.6.4"
+      }
+    },
     "qrcode": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz",
diff --git a/pass/package.json b/pass/package.json
index c8e17ec1c4c64bd4fc75f9f38aa84da7121c1302..2d05c6de58f876ad0e900da71d9c5aede1f34d85 100644
--- a/pass/package.json
+++ b/pass/package.json
@@ -29,6 +29,7 @@
     "multer": "^1.4.5-lts.1",
     "node-forge": "^1.3.1",
     "pdfkit": "^0.13.0",
+    "qr-scanner": "^1.4.2",
     "qrcode": "^1.5.1",
     "qrcode-reader": "^1.0.4",
     "uuid": "^9.0.0"
@@ -36,4 +37,4 @@
   "devDependencies": {
     "nodemon": "^2.0.20"
   }
-}
\ No newline at end of file
+}
diff --git a/pass/routes/authentication.js b/pass/routes/authentication.js
index 2ea54f72e8cdfbecf754b11f0bbdfb0841f48ac6..fe974fdc957e2c0306827bef406bb2db43db88e6 100644
--- a/pass/routes/authentication.js
+++ b/pass/routes/authentication.js
@@ -17,18 +17,20 @@ router.use(
   // General Optional authorization for every page
   // It will not require login or start a session by default
   // Only when a route uses the middleware requireAuth
-  auth({
-    issuerBaseURL: `${config.get("app.openid_auth.url")}`,
-    baseURL: config.get("app.url"),
-    clientID: config.get("app.openid_auth.app_id"),
-    clientSecret: config.get("app.openid_auth.app_secret"),
-    secret: config.get("app.secret"),
-    session: {
-      rollingDuration: auth_session_expiration_seconds,
-      signSessionStoreCookie: true,
-    },
-    authRequired: false,
-  }),
+  (req, res, next) => {
+    auth({
+      issuerBaseURL: `${config.get("app.openid_auth.url")}`,
+      baseURL: res.locals.baseDir,
+      clientID: config.get("app.openid_auth.app_id"),
+      clientSecret: config.get("app.openid_auth.app_secret"),
+      secret: config.get("app.secret"),
+      session: {
+        rollingDuration: auth_session_expiration_seconds,
+        signSessionStoreCookie: true,
+      },
+      authRequired: false,
+    })(req, res, next);
+  },
   /**
    * If the user is already authenticated this middleware will check
    * if the user inherits the required role in his oidc token to use this app
@@ -68,7 +70,7 @@ router.use(
       } else {
         let params = req.query;
         delete params.moderation;
-        let redirect_url = `${req.path}?${new URLSearchParams(
+        let redirect_url = `${res.locals.baseDir}${req.path}?${new URLSearchParams(
           params
         ).toString()}`;
         res.redirect(redirect_url);
diff --git a/pass/routes/checkout/paypal.js b/pass/routes/checkout/paypal.js
index 762b5cde338188869ca2d40fa75be891801a97da..a2e23e8f283542489a4fc0ec9b8c126615433f62 100644
--- a/pass/routes/checkout/paypal.js
+++ b/pass/routes/checkout/paypal.js
@@ -36,21 +36,21 @@ router.get("/:funding_source", async (req, res) => {
   }
 
   req.data.change_url.funding_source =
-    "/key/" +
+    `${res.locals.baseDir}/key/` +
     encodeURIComponent(req.data.key.key) +
     "/checkout/" +
     encodeURIComponent(req.data.checkout.amount) +
     "#payment";
 
   req.data.change_url.funding_source_not_eligible =
-    "/key/" +
+    `${res.locals.baseDir}/key/` +
     encodeURIComponent(req.data.key.key) +
     "/checkout/" +
     encodeURIComponent(req.data.checkout.amount) +
     "?error=funding_source_not_eligible";
 
   req.data.change_url.order_base_url =
-    "/key/" +
+    `${res.locals.baseDir}/key/` +
     encodeURIComponent(req.data.key.key) +
     "/checkout/" +
     encodeURIComponent(req.data.checkout.amount) +
@@ -142,7 +142,7 @@ router.post("/:funding_source/order/capture", async (req, res) => {
         .then(() => loaded_order.chargeKey())
         .then(() => {
           let redirect_url =
-            "/key/" + req.data.key.key + "/orders/" + loaded_order.getOrderID();
+            `${res.locals.baseDir}/key/` + req.data.key.key + "/orders/" + loaded_order.getOrderID();
           res.status(200).json({
             redirect_url: redirect_url,
             order: {
diff --git a/pass/routes/key.js b/pass/routes/key.js
index 5ee3ec5750a0d421953d05ac92217ab251b8eed8..a14acb7ea6793f6756c92303e1e0b7dd51a17fb9 100644
--- a/pass/routes/key.js
+++ b/pass/routes/key.js
@@ -101,7 +101,7 @@ router.use("/:key", param("key").isUUID(4), async (req, res, next) => {
     encodeURIComponent(req.params.key);
   let QRCode = require("qrcode");
 
-  let qr_data_uri = await QRCode.toDataURL(metager_url);
+  let qr_data_uri = await QRCode.toDataURL(metager_url, { errorCorrectionLevel: 'H', scale: 8 });
 
   req.data = Object.assign(req.data, {
     created_new: req.query.new === "true" ? true : false,
@@ -122,18 +122,19 @@ router.use("/:key", param("key").isUUID(4), async (req, res, next) => {
     css: [`${res.locals.baseDir}/styles/key/key.css`],
   });
 
-  if (!req.data.admin && (!req.cookies.key || req.cookies.key !== req.data.key.key)) {
-    res.cookie("key", req.data.key.key, {
-      sameSite: "lax"
-    });
-  }
-
   next("route");
 });
 
 // Basic account page
 router.get("/:key", async (req, res) => {
-  res.render("key", req.data);
+  if (!req.data.admin && (!req.cookies.key || req.cookies.key !== req.data.key.key)) {
+    res.cookie("key", req.data.key.key, {
+      sameSite: "lax"
+    });
+    res.render("key", req.data);
+  } else {
+    res.redirect(`${res.locals.baseDir}/logout`);
+  }
 });
 
 router.use("/:key/orders", orderRouter);
diff --git a/pass/routes/orders/invoice.js b/pass/routes/orders/invoice.js
index 3a699f7a9e66489bb9ac396ee83b84149dbae78b..7d5ed3a9dc9dcebee7d9d4ceed79fed89334ee19 100644
--- a/pass/routes/orders/invoice.js
+++ b/pass/routes/orders/invoice.js
@@ -12,9 +12,8 @@ router.get("/", (req, res) => {
       email: req.query.email || "",
       address: req.query.address || "",
     },
-    create_invoice_url: `/key/${
-      req.data.key.key
-    }/orders/${req.data.order.order.getOrderID()}/invoice/create`,
+    create_invoice_url: `${res.locals.baseDir}/key/${req.data.key.key
+      }/orders/${req.data.order.order.getOrderID()}/invoice/create`,
     errors: {},
   };
 
@@ -72,11 +71,10 @@ router.post(
       address: req.data.order.invoice.params.address,
     };
 
-    req.data.order.invoice.moderation_url = `${config.get("app.url")}/key/${
-      req.data.key.key
-    }/orders/${req.data.order.order.getOrderID()}/invoice?${new URLSearchParams(
-      moderation_params
-    ).toString()}#invoice-form`;
+    req.data.order.invoice.moderation_url = `${res.locals.baseDir}/key/${req.data.key.key
+      }/orders/${req.data.order.order.getOrderID()}/invoice?${new URLSearchParams(
+        moderation_params
+      ).toString()}#invoice-form`;
 
     // Render the message
     let ejs = require("ejs"),
@@ -157,8 +155,7 @@ router.post(
       .then(() => {
         // Added receipt. We can redirect to download page
         res.redirect(
-          `/key/${
-            req.data.key.key
+          `${res.locals.baseDir}/key/${req.data.key.key
           }/orders/${req.data.order.order.getOrderID()}/invoice/download`
         );
       })
diff --git a/pass/routes/orders/orders.js b/pass/routes/orders/orders.js
index 60b2372518bc6c6ac65dc2c9448cf9a4b3f96036..c8fa13176e58f7c139033515985cd4a39bcc42b7 100644
--- a/pass/routes/orders/orders.js
+++ b/pass/routes/orders/orders.js
@@ -16,16 +16,15 @@ router.use("/", (req, res, next) => {
 });
 router.get("/", (req, res, next) => {
   req.data.page = "order";
-  req.data.css.push("/styles/orders/orders.css");
+  req.data.css.push(`${res.locals.baseDir}/styles/orders/orders.css`);
   res.render("key", req.data);
 });
 
 router.post("/", (req, res, next) => {
-  console.log(req.body["order-id"]);
-  let matches = req.body["order-id"].match(/^(INV_)?(\d{14})$/);
+  let matches = req.body["order-id"].match(/^(INV_)?(\d+)$/);
   if (!matches) {
     req.data.page = "order";
-    req.data.css.push("/styles/orders/orders.css");
+    req.data.css.push(`${res.locals.baseDir}/styles/orders/orders.css`);
     req.data.error = 400;
     req.data.form = {
       "order-id": req.body["order-id"],
@@ -34,16 +33,16 @@ router.post("/", (req, res, next) => {
   } else {
     let order_id = matches[2];
     Order.LOAD_ORDER_FROM_ID(order_id)
-      .then(/** @param {Order} order */ (order) => order.getKeyFromOrderLink())
+      .then(/** @param {Order} order */(order) => order.getKeyFromOrderLink())
       .then((key) => {
         if (key !== req.data.key.key) {
           throw "Order is not connected to this key";
         }
-        res.redirect(`/key/${req.data.key.key}/orders/${order_id}`);
+        res.redirect(`${res.locals.baseDir}/key/${req.data.key.key}/orders/${order_id}`);
       })
       .catch((reason) => {
         req.data.page = "order";
-        req.data.css.push("/styles/orders/orders.css");
+        req.data.css.push(`${res.locals.baseDir}/styles/orders/orders.css`);
         req.data.error = 404;
         req.data.form = {
           "order-id": req.body["order-id"],
@@ -67,16 +66,15 @@ router.use("/:order_id", param("order_id").isInt(), (req, res, next) => {
     .then((order) => {
       res.cookie("order", order.getOrderID());
       req.data.page = "order";
-      req.data.css.push("/styles/orders/order.css");
+      req.data.css.push(`${res.locals.baseDir}/styles/orders/order.css`);
       req.data.order = { order: order };
-      req.data.links.order_url = `/key/${req.data.key.key}/orders/${req.params.order_id}#order`;
-      req.data.links.receipt_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/pdf`;
-      req.data.links.invoice_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/invoice#invoice-form`;
-      req.data.links.refund_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/refund#refund-form`;
+      req.data.links.order_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}#order`;
+      req.data.links.receipt_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}/pdf`;
+      req.data.links.invoice_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}/invoice#invoice-form`;
+      req.data.links.refund_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}/refund#refund-form`;
       if (req.data.order.order.isReceiptCreated()) {
-        req.data.order.download_invoice_url = `/key/${
-          req.data.key.key
-        }/orders/${req.data.order.order.getOrderID()}/invoice/download`;
+        req.data.order.download_invoice_url = `${res.locals.baseDir}/key/${req.data.key.key
+          }/orders/${req.data.order.order.getOrderID()}/invoice/download`;
       }
       next("route");
     })