diff --git a/CHANGELOG.md b/CHANGELOG.md
index 096dbb5a5bf8e317f976934d6622ea8567d323ca..85f2c54d557a483b80bc872cf6114cd0afa550dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # Changelog
 
+## [0.6.3]
+
+- Add support for Hedgedoc.
+- Add a button for admins for creating a recovery link for a user.
+- Automatically log in to dashboard if already authenticated.
+- Redirect to dashboard if not redirect login is set, on successful login.
+- Fix deletion of apps via the CLI.
+- Add special features (sign-up form) for the Stackspin demo instance.
+- Show the user UUID in user modal.
+- Only show installed apps when configuring roles.
+
 ## [0.6.2]
 
 - Fix submit button label in the form for verifying your TOTP code.
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 67b11bb62970ef62261b83e1adf933322de99af2..90f087405cedb845074e0b05b274d0c500b75fa0 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -24,4 +24,4 @@ COPY . .
 EXPOSE 5000
 
 # Define our command to be run when launching the container
-CMD ["gunicorn", "app:app", "-b", "0.0.0.0:5000", "--workers", "4", "--reload", "--capture-output", "--enable-stdio-inheritance", "--log-level", "DEBUG"]
+CMD ["gunicorn", "app:app", "-b", "0.0.0.0:5000", "--workers", "8", "--reload", "--capture-output", "--enable-stdio-inheritance", "--log-level", "DEBUG"]
diff --git a/backend/areas/apps/models.py b/backend/areas/apps/models.py
index 73fd15504b59b73df5681773d33e0bd2e63b7822..e7898a14c1c67f40ff2d27176c7f7c30c861d653 100644
--- a/backend/areas/apps/models.py
+++ b/backend/areas/apps/models.py
@@ -165,7 +165,7 @@ class App(db.Model):
 
         FIXME: This should probably become a database field.
         """
-        if self.slug in ['nextcloud', 'wordpress', 'wekan', 'zulip']:
+        if self.slug in ['nextcloud', 'wordpress', 'wekan', 'zulip', 'hedgedoc']:
             return 'stackspin-apps'
         return 'stackspin'
 
diff --git a/backend/areas/apps/templates/stackspin-hedgedoc-variables.yaml.jinja b/backend/areas/apps/templates/stackspin-hedgedoc-variables.yaml.jinja
new file mode 100644
index 0000000000000000000000000000000000000000..e0d339621b60c815d04003a1fe8780507e0fae57
--- /dev/null
+++ b/backend/areas/apps/templates/stackspin-hedgedoc-variables.yaml.jinja
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: stackspin-hedgedoc-variables
+data:
+  hedgedoc_mariadb_password: "{{ 32 | generate_password | b64encode }}"
+  hedgedoc_mariadb_root_password: "{{ 32 | generate_password | b64encode }}"
diff --git a/backend/areas/users/user_service.py b/backend/areas/users/user_service.py
index 99169f5656437150e21bc611c0a08812288feb36..75166d12474e31d8781e63e2eec703a43cb0b8da 100644
--- a/backend/areas/users/user_service.py
+++ b/backend/areas/users/user_service.py
@@ -34,6 +34,14 @@ class UserService:
         res = KratosApi.get("/admin/identities/{}".format(id)).json()
         return UserService.__insertAppRoleToUser(id, res)
 
+    @staticmethod
+    def create_recovery_link(id):
+        kratos_data = {
+            "identity_id": id
+        }
+        res = KratosApi.post("/admin/recovery/link", kratos_data).json()
+        return res
+
     @staticmethod
     def post_user(data):
         kratos_data = {
diff --git a/backend/areas/users/users.py b/backend/areas/users/users.py
index b1740ebd57eba73348a1ac4127d2f8652261368c..25d906e593b405cb9a6a19f21a44f123194c181a 100644
--- a/backend/areas/users/users.py
+++ b/backend/areas/users/users.py
@@ -28,6 +28,13 @@ def get_user(id):
     res = UserService.get_user(id)
     return jsonify(res)
 
+@api_v1.route("/users/<string:id>/recovery", methods=["POST"])
+@jwt_required()
+@cross_origin()
+@admin_required()
+def get_user_recovery(id):
+    res = UserService.create_recovery_link(id)
+    return jsonify(res)
 
 @api_v1.route("/users", methods=["POST"])
 @jwt_required()
diff --git a/backend/web/static/base.js b/backend/web/static/base.js
index e7cab4a0d962dec9018d14fe703cb784a1a612da..a2cf2f18a5dbde19742883e1de748804a8a997f1 100644
--- a/backend/web/static/base.js
+++ b/backend/web/static/base.js
@@ -16,16 +16,32 @@
 
 */
 
+// In default configuration the dashboed is on '/'. This can be overwritten
+// before calling the scripts (and configured by the flask app
+var dashboard_url = '';
+
 // Check if an auth flow is configured and redirect to auth page in that
 // case.
 function check_flow_auth() {
   var state = Cookies.get('flow_state');
   var url = Cookies.get('auth_url');
 
+  // Redirect to the specified URL
   if (state == 'auth') {
     Cookies.set('flow_state', '');
     window.location.href = url;
+    return;
+  }
+
+  // Some older stackspin releases, do not provide the dashboard_url,
+  // flask writes 'None' as string in that case, we want to cover those
+  // cases and revert to the default
+  if (dashboard_url == 'None'|| dashboard_url == '') {
+    dashboard_url = window.location.protocol + "//" + window.location.host;
   }
+
+  // If no redirect is set, redirect to dashboard
+  window.location.href = dashboard_url + '/login';
 }
 
 // Check if there if the flow is expired, if so, reset the cookie
diff --git a/backend/web/templates/loggedin.html b/backend/web/templates/loggedin.html
index aee728efd7af9818830128570bcc6a95f5ab4f1a..51b35cd13e744db651d78e077defa86b2309a26f 100644
--- a/backend/web/templates/loggedin.html
+++ b/backend/web/templates/loggedin.html
@@ -4,6 +4,7 @@
 
 <script>
     var api_url = '{{ api_url }}';
+    var dashboard_url = '{{ dashboard_url }}';
 
     // Actions
     $(document).ready(function() {
@@ -17,8 +18,7 @@
 
 <div id="contentMessages"></div>
 <div id="contentWelcome">
-    Welcome{{ name }}, you are logged in.
+    Welcome{{ name }}, you are logged in. We are redirecting you....
 </div>
 
-
 {% endblock %}
diff --git a/deployment/helmchart/Chart.yaml b/deployment/helmchart/Chart.yaml
index c32b4ac2d2292c7941a5d0e924ad770dd2b6b4bb..f47e974e8f0c03f16e0fff03170a269f8e8d2c43 100644
--- a/deployment/helmchart/Chart.yaml
+++ b/deployment/helmchart/Chart.yaml
@@ -1,7 +1,7 @@
 annotations:
   category: Dashboard
 apiVersion: v2
-appVersion: 0.6.2
+appVersion: 0.6.3
 dependencies:
   - name: common
     # https://artifacthub.io/packages/helm/bitnami/common
@@ -23,4 +23,4 @@ name: stackspin-dashboard
 sources:
   - https://open.greenhost.net/stackspin/dashboard/
   - https://open.greenhost.net/stackspin/dashboard-backend/
-version: 1.6.2
+version: 1.6.3
diff --git a/deployment/helmchart/templates/job-initialize-user.yaml b/deployment/helmchart/templates/job-initialize-user.yaml
index 4cf77350d3cbfbd3b2defeb9e3f732397d8ab95b..a1d6d1d95edeebb0c1a9762ed94daf6c2cb66b96 100644
--- a/deployment/helmchart/templates/job-initialize-user.yaml
+++ b/deployment/helmchart/templates/job-initialize-user.yaml
@@ -56,5 +56,6 @@ spec:
             flask cli user setrole $SETUP_EMAIL wordpress admin;
             flask cli user setrole $SETUP_EMAIL wekan admin;
             flask cli user setrole $SETUP_EMAIL zulip admin;
+            flask cli user setrole $SETUP_EMAIL hedgedoc admin;
             {{- end }}
 
diff --git a/deployment/helmchart/values.yaml b/deployment/helmchart/values.yaml
index 343d5e54976054598bd4a4e85c7c8b342118f84c..3f0dce93f91925316ec55fae3de1f9bc98437b0d 100644
--- a/deployment/helmchart/values.yaml
+++ b/deployment/helmchart/values.yaml
@@ -68,7 +68,7 @@ dashboard:
   image:
     registry: open.greenhost.net:4567
     repository: stackspin/dashboard/dashboard
-    tag: 0.6.2
+    tag: 0.6.3
     digest: ""
     ## Optionally specify an array of imagePullSecrets.
     ## Secrets must be manually created in the namespace.
@@ -236,7 +236,7 @@ backend:
   image:
     registry: open.greenhost.net:4567
     repository: stackspin/dashboard/dashboard-backend
-    tag: 0.6.2
+    tag: 0.6.3
     digest: ""
     ## Optionally specify an array of imagePullSecrets.
     ## Secrets must be manually created in the namespace.
diff --git a/docker-compose.yml b/docker-compose.yml
index 655be3e58c31e6d70fefdab2b1f40398e6fee636..97f22787fdad1b02ef892d88e2dcac8f1bbdacc6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -56,7 +56,7 @@ services:
       - kube_port_mysql
     entrypoint: ["bash", "-c", "flask run --host $$(hostname -i)"]
   kube_port_kratos_admin:
-    image: bitnami/kubectl:1.26.2
+    image: bitnami/kubectl:1.26.3
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     expose:
       - 8000
@@ -64,7 +64,7 @@ services:
       - "$KUBECONFIG:/.kube/config"
     entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/kratos-admin 8000:80"]
   kube_port_hydra_admin:
-    image: bitnami/kubectl:1.26.2
+    image: bitnami/kubectl:1.26.3
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     expose:
       - 4445
@@ -72,7 +72,7 @@ services:
       - "$KUBECONFIG:/.kube/config"
     entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/hydra-admin 4445:4445"]
   kube_port_kratos_public:
-    image: bitnami/kubectl:1.26.2
+    image: bitnami/kubectl:1.26.3
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     ports:
       - "8080:8080"
@@ -82,7 +82,7 @@ services:
       - "$KUBECONFIG:/.kube/config"
     entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address 0.0.0.0 service/kratos-public 8080:80"]
   kube_port_mysql:
-    image: bitnami/kubectl:1.26.2
+    image: bitnami/kubectl:1.26.3
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     expose:
       - 3306
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 6a7e219519bfc587a3d30f0548cb142c43ca94fc..47b5c6e1663564403d8cc7435d091d709009911c 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -4,7 +4,7 @@ WORKDIR /home/node/app
 
 # First copy only files necessary for installing dependencies, so that we can
 # cache that step even when our own source code changes.
-COPY package.json yarn.lock .
+COPY package.json yarn.lock ./
 
 RUN yarn install
 
diff --git a/frontend/public/assets/hedgedoc.svg b/frontend/public/assets/hedgedoc.svg
new file mode 100644
index 0000000000000000000000000000000000000000..e561ed32ce807fbf12f014d9d9c5d86a32a30975
--- /dev/null
+++ b/frontend/public/assets/hedgedoc.svg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg width="100%" height="100%" viewBox="0 0 1772 1772" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
+    <g>
+        <path d="M1553.66,961.083L1628.91,885.825L1553.66,810.579L1610.27,720.483L1520.17,663.867L1555.32,563.421L1454.88,528.279L1466.79,422.533L1361.05,410.621L1349.13,304.871L1243.39,316.783L1208.24,216.338L1107.81,251.483L1051.18,161.383L961.073,218L885.831,142.754L810.589,218.004L720.485,161.392L663.873,251.488L563.431,216.338L528.289,316.779L422.539,304.863L410.627,410.604L304.885,422.517L316.802,528.258L216.348,563.408L251.493,663.846L161.393,720.458L218.014,810.575L142.756,885.825L218.006,961.083L161.393,1051.19L251.493,1107.8L216.348,1208.24L316.798,1243.39L304.885,1349.12L410.627,1361.04L422.539,1466.78L528.289,1454.87L563.431,1555.3L663.868,1520.17L720.485,1610.27L810.581,1553.65L885.831,1628.2L961.081,1553.67L1051.18,1610.28L1107.79,1520.17L1208.24,1555.32L1243.38,1454.88L1349.13,1466.79L1361.04,1361.04L1466.79,1349.13L1454.87,1243.39L1555.32,1208.24L1520.17,1107.79L1610.27,1051.18L1553.66,961.083Z" style="fill:rgb(181,31,8);fill-rule:nonzero;"/>
+        <path d="M1401.3,1004.78C1401.3,859.343 1283.4,741.439 1137.96,741.439C1065.72,741.439 1000.28,770.551 952.708,817.664L952.675,817.63L885.579,884.73L830.717,829.868C782.45,774.801 711.646,739.989 632.675,739.989C487.233,739.989 369.333,857.893 369.333,1003.33C369.333,1079.33 401.563,1147.76 453.054,1195.82L885.833,1628.37L1309.05,1204.88C1361.93,1155.11 1401.3,1084.88 1401.3,1004.78" style="fill:rgb(252,202,140);fill-rule:nonzero;"/>
+        <path d="M885.579,884.73L830.717,829.868C782.45,774.801 711.646,739.989 632.675,739.989C487.233,739.989 369.333,857.893 369.333,1003.33C369.333,1079.33 401.563,1147.76 453.054,1195.82L885.833,1628.37" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
+    </g>
+    <path d="M885.833,1628.37L885.579,884.73" style="fill:none;"/>
+    <g>
+        <path d="M961.011,1553.59C941.732,1534.24 915.094,1522.28 885.686,1522.28C856.269,1522.28 829.64,1534.24 810.357,1553.59C810.665,1594.93 844.265,1628.35 885.682,1628.35C927.098,1628.35 960.702,1594.92 961.011,1553.59" style="fill:rgb(1,0,7);fill-rule:nonzero;"/>
+        <path d="M797.707,1098.22C797.707,1130.02 771.94,1155.79 740.136,1155.79C708.349,1155.79 682.578,1130.02 682.578,1098.22C682.578,1066.42 708.349,1040.65 740.136,1040.65C771.94,1040.65 797.707,1066.42 797.707,1098.22" style="fill:rgb(1,0,7);fill-rule:nonzero;"/>
+        <path d="M777.962,1089.59C777.962,1098.41 770.816,1105.53 762.012,1105.53C753.204,1105.53 746.054,1098.41 746.054,1089.59C746.054,1080.78 753.204,1073.63 762.012,1073.63C770.816,1073.63 777.962,1080.78 777.962,1089.59" style="fill:rgb(255,255,250);fill-rule:nonzero;"/>
+        <path d="M1089.65,1098.22C1089.65,1130.02 1063.88,1155.79 1032.08,1155.79C1000.29,1155.79 974.513,1130.02 974.513,1098.22C974.513,1066.42 1000.29,1040.65 1032.08,1040.65C1063.88,1040.65 1089.65,1066.42 1089.65,1098.22" style="fill:rgb(1,0,7);fill-rule:nonzero;"/>
+        <path d="M1069.9,1089.59C1069.9,1098.41 1062.75,1105.53 1053.95,1105.53C1045.14,1105.53 1037.99,1098.41 1037.99,1089.59C1037.99,1080.78 1045.14,1073.63 1053.95,1073.63C1062.75,1073.63 1069.9,1080.78 1069.9,1089.59" style="fill:rgb(255,255,250);fill-rule:nonzero;"/>
+    </g>
+    <defs>
+        <linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(200,-420,420,200,660,1340)"><stop offset="0" style="stop-color:rgb(252,202,140);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(220,160,85);stop-opacity:1"/></linearGradient>
+    </defs>
+</svg>
diff --git a/frontend/src/components/Modal/InfoModal/InfoModal.tsx b/frontend/src/components/Modal/InfoModal/InfoModal.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..2e69dba8df25d75b151d5a4bc8fa6ba96289849f
--- /dev/null
+++ b/frontend/src/components/Modal/InfoModal/InfoModal.tsx
@@ -0,0 +1,86 @@
+import React, { Fragment, useRef } from 'react';
+import { Dialog, Transition } from '@headlessui/react';
+import { InformationCircleIcon } from '@heroicons/react/outline';
+
+type InfoModalProps = {
+  open: boolean;
+  onClose: () => void;
+  title: string;
+  body: string;
+  dynamicData: string;
+};
+
+export const InfoModal = ({ open, onClose, title, body, dynamicData }: InfoModalProps) => {
+  const cancelButtonRef = useRef(null);
+
+  return (
+    <Transition.Root show={open} as={Fragment}>
+      <Dialog
+        as="div"
+        auto-reopen="true"
+        className="fixed z-10 inset-0 overflow-y-auto"
+        initialFocus={cancelButtonRef}
+        onClose={onClose}
+      >
+        <div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
+          <Transition.Child
+            as={Fragment}
+            enter="ease-out duration-300"
+            enterFrom="opacity-0"
+            enterTo="opacity-100"
+            leave="ease-in duration-200"
+            leaveFrom="opacity-100"
+            leaveTo="opacity-0"
+          >
+            <Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
+          </Transition.Child>
+
+          {/* This element is to trick the browser into centering the modal contents. */}
+          <span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
+            &#8203;
+          </span>
+          <Transition.Child
+            as={Fragment}
+            enter="ease-out duration-300"
+            enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
+            enterTo="opacity-100 translate-y-0 sm:scale-100"
+            leave="ease-in duration-200"
+            leaveFrom="opacity-100 translate-y-0 sm:scale-100"
+            leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
+          >
+            <div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
+              <div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
+                <div className="sm:flex sm:items-start">
+                  <div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
+                    <InformationCircleIcon className="h-6 w-6 text-blue-600" aria-hidden="true" />
+                  </div>
+                  <div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
+                    <Dialog.Title as="h3" className="text-lg leading-6 font-medium text-gray-900">
+                      {title}
+                    </Dialog.Title>
+                    <div className="mt-2">
+                      <p className="text-sm text-gray-500">{body}</p>
+                    </div>
+                    <div className="mt-2">
+                      <p className="text-sm text-gray-500">{dynamicData}</p>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
+                <button
+                  type="button"
+                  className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
+                  onClick={onClose}
+                  ref={cancelButtonRef}
+                >
+                  Close
+                </button>
+              </div>
+            </div>
+          </Transition.Child>
+        </div>
+      </Dialog>
+    </Transition.Root>
+  );
+};
diff --git a/frontend/src/components/Modal/InfoModal/index.ts b/frontend/src/components/Modal/InfoModal/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3e5e1e455deebba6d3d6df928e83523181e2fd35
--- /dev/null
+++ b/frontend/src/components/Modal/InfoModal/index.ts
@@ -0,0 +1 @@
+export { InfoModal } from './InfoModal';
diff --git a/frontend/src/components/Modal/index.ts b/frontend/src/components/Modal/index.ts
index e5800df0cd61eb051c8456da27e6abece8183ee3..32c47ffa647c559df41093cc9ca66e9f4ae19419 100644
--- a/frontend/src/components/Modal/index.ts
+++ b/frontend/src/components/Modal/index.ts
@@ -1,3 +1,4 @@
 export { ConfirmationModal } from './ConfirmationModal';
+export { InfoModal } from './InfoModal';
 export { Modal } from './Modal';
 export { StepsModal } from './StepsModal';
diff --git a/frontend/src/components/UserModal/UserModal.tsx b/frontend/src/components/UserModal/UserModal.tsx
index 5e64122718e2f356ee8f7837e9ee6c525c896819..b6ceed73710f45f3bda1e4218224c85fbec575fd 100644
--- a/frontend/src/components/UserModal/UserModal.tsx
+++ b/frontend/src/components/UserModal/UserModal.tsx
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
 import _ from 'lodash';
 import { TrashIcon } from '@heroicons/react/outline';
 import { useFieldArray, useForm, useWatch } from 'react-hook-form';
-import { Banner, Modal, ConfirmationModal } from 'src/components';
+import { Banner, Modal, ConfirmationModal, InfoModal } from 'src/components';
 import { Input, Select } from 'src/components/Form';
 import { User, UserRole, useUsers } from 'src/services/users';
 import { useAuth } from 'src/services/auth';
@@ -12,10 +12,12 @@ import { UserModalProps } from './types';
 
 export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps) => {
   const [deleteModal, setDeleteModal] = useState(false);
+  const [passwordLinkModal, setPasswordLinkModal] = useState(false);
   const [isAdminRoleSelected, setAdminRoleSelected] = useState(true);
   const [isPersonalModal, setPersonalModal] = useState(false);
   const {
     user,
+    recoveryLink,
     loadUser,
     loadPersonalInfo,
     editUserById,
@@ -23,6 +25,7 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
     createNewUser,
     userModalLoading,
     deleteUserById,
+    getRecoveryLinkUserById,
     clearSelectedUser,
   } = useUsers();
   const { currentUser, isAdmin } = useAuth();
@@ -108,6 +111,15 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
   const deleteModalOpen = () => setDeleteModal(true);
   const deleteModalClose = () => setDeleteModal(false);
 
+  const passwordLinkModalOpen = () => {
+    if (userId) {
+      getRecoveryLinkUserById(userId);
+    }
+    setPasswordLinkModal(true);
+  };
+
+  const passwordLinkModalClose = () => setPasswordLinkModal(false);
+
   const handleDelete = () => {
     if (userId) {
       deleteUserById(userId);
@@ -119,6 +131,40 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
     deleteModalClose();
   };
 
+  // Button with delete option.
+  const buttonDelete = () => {
+    return (
+      userId &&
+      user.email !== currentUser?.email && (
+        <button
+          onClick={deleteModalOpen}
+          type="button"
+          className="mb-4 sm:mb-0 inline-flex items-center px-4 py-2 text-sm font-medium rounded-md text-red-700 bg-red-50 hover:bg-red-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
+        >
+          <TrashIcon className="-ml-0.5 mr-2 h-4 w-4" aria-hidden="true" />
+          Delete
+        </button>
+      )
+    );
+  };
+
+  // Button to generate password link
+  const buttonPasswordLink = () => {
+    return (
+      userId &&
+      isAdmin && (
+        <button
+          onClick={passwordLinkModalOpen}
+          type="button"
+          className="mb-4 sm:mb-0 inline-flex items-center px-4 py-2 text-sm
+  font-medium rounded-md text-blue-700 bg-blue-50 hover:bg-blue-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
+        >
+          Password Link
+        </button>
+      )
+    );
+  };
+
   return (
     <>
       <Modal
@@ -127,17 +173,10 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
         onSave={handleSave}
         isLoading={userModalLoading}
         leftActions={
-          userId &&
-          user.email !== currentUser?.email && (
-            <button
-              onClick={deleteModalOpen}
-              type="button"
-              className="mb-4 sm:mb-0 inline-flex items-center px-4 py-2 text-sm font-medium rounded-md text-red-700 bg-red-50 hover:bg-red-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
-            >
-              <TrashIcon className="-ml-0.5 mr-2 h-4 w-4" aria-hidden="true" />
-              Delete
-            </button>
-          )
+          <>
+            {buttonDelete()}
+            {buttonPasswordLink()}
+          </>
         }
         useCancelButton
       >
@@ -206,7 +245,6 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
                 )}
               </div>
             </div>
-
             {isAdmin && !userModalLoading && (
               <div>
                 <div className="mt-8">
@@ -270,7 +308,6 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
           </div>
         </div>
       </Modal>
-
       <ConfirmationModal
         onDeleteAction={handleDelete}
         open={deleteModal}
@@ -278,6 +315,13 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
         title="Delete user"
         body="Are you sure you want to delete this user? All of the user data will be permanently removed. This action cannot be undone."
       />
+      <InfoModal
+        open={passwordLinkModal}
+        onClose={passwordLinkModalClose}
+        title="Password reset link"
+        body="Below is a password reset link. Copy this link and send to the user to reset the password without using e-mail"
+        dynamicData={recoveryLink}
+      />
     </>
   );
 };
diff --git a/frontend/src/components/UserModal/consts.ts b/frontend/src/components/UserModal/consts.ts
index 95cbbf0812a22ca98c2b1b1230a16b51c4426845..ebf5a1f93be1338ba981d95c5b8f29fd41e28eb7 100644
--- a/frontend/src/components/UserModal/consts.ts
+++ b/frontend/src/components/UserModal/consts.ts
@@ -1,6 +1,12 @@
 import { UserRole } from 'src/services/users';
 
 export const appAccessList = [
+  {
+    name: 'hedgedoc',
+    image: '/assets/hedgedoc.svg',
+    label: 'HedgeDoc',
+    documentationUrl: 'https://docs.hedgedoc.org/',
+  },
   {
     name: 'wekan',
     image: '/assets/wekan.svg',
@@ -47,6 +53,10 @@ export const initialAppRoles = [
     name: 'dashboard',
     role: UserRole.User,
   },
+  {
+    name: 'hedgedoc',
+    role: UserRole.User,
+  },
   {
     name: 'wekan',
     role: UserRole.User,
diff --git a/frontend/src/components/index.ts b/frontend/src/components/index.ts
index 9a2f607cfeb960268b04186d98cfc92dcd0c9abc..64e430d54ff3ea8a1af2dae1ab0feac9e7c82450 100644
--- a/frontend/src/components/index.ts
+++ b/frontend/src/components/index.ts
@@ -3,6 +3,6 @@ export { Header } from './Header';
 export { Table } from './Table';
 export { Banner } from './Banner';
 export { Tabs } from './Tabs';
-export { Modal, ConfirmationModal, StepsModal } from './Modal';
+export { Modal, ConfirmationModal, InfoModal, StepsModal } from './Modal';
 export { UserModal } from './UserModal';
 export { ProgressSteps } from './ProgressSteps';
diff --git a/frontend/src/services/users/hooks/use-users.ts b/frontend/src/services/users/hooks/use-users.ts
index 2d0381de36faf88771aab5af1e9e033f455a68fc..447bcce90e083a48866ad1a26b9e0e6b788225e1 100644
--- a/frontend/src/services/users/hooks/use-users.ts
+++ b/frontend/src/services/users/hooks/use-users.ts
@@ -10,13 +10,15 @@ import {
   deleteUser,
   clearCurrentUser,
   createBatchUsers,
+  fetchRecoveryLink,
 } from '../redux';
-import { getUserById, getUserModalLoading, getUserslLoading } from '../redux/selectors';
+import { getUserById, getRecoveryLink, getUserModalLoading, getUserslLoading } from '../redux/selectors';
 
 export function useUsers() {
   const dispatch = useDispatch();
   const users = useSelector(getUsers);
   const user = useSelector(getUserById);
+  const recoveryLink = useSelector(getRecoveryLink);
   const userModalLoading = useSelector(getUserModalLoading);
   const userTableLoading = useSelector(getUserslLoading);
 
@@ -55,10 +57,14 @@ export function useUsers() {
   function deleteUserById(id: string) {
     return dispatch(deleteUser(id));
   }
+  function getRecoveryLinkUserById(id: string) {
+    return dispatch(fetchRecoveryLink(id));
+  }
 
   return {
     users,
     user,
+    recoveryLink,
     loadUser,
     loadUsers,
     loadPersonalInfo,
@@ -68,6 +74,7 @@ export function useUsers() {
     userTableLoading,
     createNewUser,
     deleteUserById,
+    getRecoveryLinkUserById,
     clearSelectedUser,
     createUsers,
   };
diff --git a/frontend/src/services/users/redux/actions.ts b/frontend/src/services/users/redux/actions.ts
index 7643b41e83586929faf4a108ec8fafae56b28331..9fc8770d4ec06109a73a736c0a9aa9e4e0ae0159 100644
--- a/frontend/src/services/users/redux/actions.ts
+++ b/frontend/src/services/users/redux/actions.ts
@@ -9,6 +9,7 @@ import {
   transformRequestMultipleUsers,
   transformRequestUser,
   transformUser,
+  transformRecoveryLink,
 } from '../transformations';
 
 export enum UserActionTypes {
@@ -17,6 +18,7 @@ export enum UserActionTypes {
   UPDATE_USER = 'users/update_user',
   CREATE_USER = 'users/create_user',
   DELETE_USER = 'users/delete_user',
+  FETCH_RECOVERY_LINK = 'users/recoverylink_user',
   SET_USER_MODAL_LOADING = 'users/user_modal_loading',
   SET_USERS_LOADING = 'users/users_loading',
   CREATE_BATCH_USERS = 'users/create_batch_users',
@@ -185,6 +187,22 @@ export const createUser = (user: any) => async (dispatch: Dispatch<any>) => {
   dispatch(setUserModalLoading(false));
 };
 
+export const fetchRecoveryLink = (id: string) => async (dispatch: Dispatch<any>) => {
+  try {
+    const { data } = await performApiCall({
+      path: `/users/${id}/recovery`,
+      method: 'POST',
+    });
+
+    dispatch({
+      type: UserActionTypes.FETCH_RECOVERY_LINK,
+      payload: transformRecoveryLink(data),
+    });
+  } catch (err) {
+    console.error(err);
+  }
+};
+
 export const deleteUser = (id: string) => async (dispatch: Dispatch<any>) => {
   dispatch(setUserModalLoading(true));
 
diff --git a/frontend/src/services/users/redux/reducers.ts b/frontend/src/services/users/redux/reducers.ts
index 2d02771db98e3c3419b651a7d9e721ce4f26c59e..d2372f589d3d83027186ab1edaaffae8c9d463fd 100644
--- a/frontend/src/services/users/redux/reducers.ts
+++ b/frontend/src/services/users/redux/reducers.ts
@@ -19,6 +19,11 @@ const usersReducer = (state: any = initialUsersState, action: any) => {
         ...state,
         userModalLoading: action.payload,
       };
+    case UserActionTypes.FETCH_RECOVERY_LINK:
+      return {
+        ...state,
+        recoveryLink: action.payload,
+      };
     case UserActionTypes.SET_USERS_LOADING:
       return {
         ...state,
diff --git a/frontend/src/services/users/redux/selectors.ts b/frontend/src/services/users/redux/selectors.ts
index 44dea21ac966565d0b3876f1f1937535119faf81..af00389ff0ccf17a6df5c5e3585495625ff1174f 100644
--- a/frontend/src/services/users/redux/selectors.ts
+++ b/frontend/src/services/users/redux/selectors.ts
@@ -4,3 +4,4 @@ export const getUsers = (state: State) => state.users.users;
 export const getUserById = (state: State) => state.users.user;
 export const getUserModalLoading = (state: State) => state.users.userModalLoading;
 export const getUserslLoading = (state: State) => state.users.usersLoading;
+export const getRecoveryLink = (state: State) => state.users.recoveryLink;
diff --git a/frontend/src/services/users/redux/types.ts b/frontend/src/services/users/redux/types.ts
index c1954ead5c95b54c675c9f477ebda8af7883bc75..4fd9f0be495e8499e37bd66a08761db307497e88 100644
--- a/frontend/src/services/users/redux/types.ts
+++ b/frontend/src/services/users/redux/types.ts
@@ -10,6 +10,7 @@ export interface UsersState {
   currentUser: CurrentUserState;
   users: User[];
   user: User;
+  recoveryLink: string;
   userModalLoading: boolean;
   usersLoading: boolean;
 }
diff --git a/frontend/src/services/users/transformations.ts b/frontend/src/services/users/transformations.ts
index 21e7db46413d1b240b861315de78fa09fb37c2a5..545c947580639e57a95b3c89ad3b2a0d3a88632a 100644
--- a/frontend/src/services/users/transformations.ts
+++ b/frontend/src/services/users/transformations.ts
@@ -91,3 +91,7 @@ export const transformBatchResponse = (response: any): any => {
     failed: response.failed,
   };
 };
+
+export const transformRecoveryLink = (response: any): string => {
+  return response.recovery_link;
+};