diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml
index 2db8fc6185c54f0595c7b170273d8d9778252712..4d33cc34e54ec5818e14827803b14006029e5a4e 100644
--- a/.docker/docker-compose.yml
+++ b/.docker/docker-compose.yml
@@ -78,11 +78,12 @@ services:
     restart: "no"
     container_name: dbrepo-auth-service
     hostname: auth-service
-    image: bitnami/keycloak:26.0.0-debian-12-r1
+    image: bitnami/keycloak:24.0.5-debian-12-r8
     volumes:
       - ./config/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh
       - ./config/master-realm.json:/opt/keycloak/data/import/master-realm.json
       - ./config/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json
+      - ./config/create-event-listener.jar:/opt/bitnami/keycloak/providers/create-event-listener.jar
     ports:
       - "8080:8080"
     environment:
@@ -92,6 +93,9 @@ services:
       KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}"
       KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}"
       KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}/api/user"
+      SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}"
+      SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}"
     healthcheck:
       test: curl -fsS http://localhost:8080/realms/master
       interval: 10s
@@ -109,7 +113,7 @@ services:
     init: true
     restart: "no"
     container_name: dbrepo-auth-service-init
-    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
     environment:
       AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin}
       AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin}
@@ -130,7 +134,7 @@ services:
     restart: "no"
     container_name: dbrepo-metadata-service
     hostname: metadata-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
@@ -193,7 +197,7 @@ services:
     restart: "no"
     container_name: dbrepo-analyse-service
     hostname: analyse-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3
     environment:
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
@@ -248,7 +252,7 @@ services:
     restart: "no"
     container_name: dbrepo-search-db
     hostname: search-db
-    image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.6.3
     healthcheck:
       test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP
       interval: 10s
@@ -272,7 +276,7 @@ services:
     restart: "no"
     container_name: dbrepo-search-service
     hostname: search-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3
     environment:
       AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client}
       AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}
@@ -296,11 +300,15 @@ services:
     restart: "no"
     container_name: dbrepo-ui
     hostname: ui
-    image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3
     environment:
       NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}"
-      NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}"
+      NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://gateway-service}"
       NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "${AUTH_SERVICE_CLIENT:-dbrepo-client}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "${BASE_URL:-http://localhost}/auth/keycloak/callback"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "${BASE_URL:-http://localhost}"
     depends_on:
       dbrepo-search-service:
         condition: service_healthy
@@ -311,6 +319,8 @@ services:
       interval: 10s
       timeout: 5s
       retries: 12
+    extra_hosts:
+      - "localhost:host-gateway"
     logging:
       driver: json-file
 
@@ -365,7 +375,7 @@ services:
     init: true
     container_name: dbrepo-search-service-init
     hostname: search-service-init
-    image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3
     environment:
       LOG_LEVEL: ${LOG_LEVEL:-info}
       METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}
@@ -422,7 +432,7 @@ services:
     restart: "no"
     container_name: dbrepo-dashboard-service
     hostname: dashboard-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.6.3
     ports:
       - "3000:3000"
     volumes:
@@ -449,7 +459,7 @@ services:
     init: true
     container_name: dbrepo-storage-service-init
     hostname: storage-service-init
-    image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3
     environment:
       S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:-seaweedfsadmin}
       S3_BUCKET: "${S3_BUCKET:-dbrepo}"
@@ -479,6 +489,7 @@ services:
       AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}"
       AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}"
       AWS_REGION: "${STORAGE_REGION_NAME:-default}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}"
     depends_on:
       dbrepo-storage-service:
         condition: service_healthy
@@ -494,7 +505,7 @@ services:
     restart: "no"
     container_name: dbrepo-data-service
     hostname: data-service
-    image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.2
+    image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3
     volumes:
       - "${SHARED_VOLUME:-/tmp}:/tmp"
     environment:
diff --git a/.docs/api/auth-service.md b/.docs/api/auth-service.md
index 93e87beaf280b5ed9b96a2aca508308098676173..7b28901a9b9d49a01d48a313187f86832509a03b 100644
--- a/.docs/api/auth-service.md
+++ b/.docs/api/auth-service.md
@@ -88,10 +88,6 @@ which is imported into Keycloak on startup.
 
 ## Limitations
 
-* No support for sending e-mails through Keycloak by default.
-* No support for temporary passwords.
-* No support for multi-factor authentication.
-
 !!! question "Do you miss functionality? Do these limitations affect you?"
 
     We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get
diff --git a/.docs/api/ui.md b/.docs/api/ui.md
index 30b32c0a0ccde771c8bde22f21ca630d6354a9b3..b82058c19bae4c4e629e0f1e06eca29985c94f67 100644
--- a/.docs/api/ui.md
+++ b/.docs/api/ui.md
@@ -101,6 +101,7 @@ See the [API Overview](..) page for detailed examples.
 
 ## Limitations
 
+* Changing the OIDC provider URL requires to build the UI from scratch.
 * When developing locally, the `axios` module does not parse custom headers (such as `X-Count`, `X-Headers`) and/or
   blocks CORS requests wrongfully.
 
diff --git a/.docs/changelog.md b/.docs/changelog.md
index e2bb59c3748fde0b9da1db9099e013fd6b928db8..efdb4dd291dbbc3194ffc3ec3168ed71befffee3 100644
--- a/.docs/changelog.md
+++ b/.docs/changelog.md
@@ -2,6 +2,17 @@
 author: Martin Weise
 ---
 
+## v1.6.3 (2025-02-05)
+
+[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.3)
+
+### What's Changed
+
+#### Changes
+
+* Refactored the UI to support OIDC and added an event listener to the Auth Service that syncs users on creation to the
+  Metadata DB in [#488](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/488).
+
 ## v1.6.2 (2025-01-24)
 
 [:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.2)
diff --git a/.docs/concepts/data-visibility.md b/.docs/concepts/data-visibility.md
index 04f37c6979bd9019d954859535a757c72da4b63e..31c6ca3682780c4353c6aa5baaae666047893635 100644
--- a/.docs/concepts/data-visibility.md
+++ b/.docs/concepts/data-visibility.md
@@ -8,28 +8,40 @@ subset of a database.
 
 ## Visibility
 
-In total there are three possible scenarios:
+In total there are four possible visibility settings that can be applied on database level and then at the subsequent
+levels (table, view, subset). We give two examples for better understanding:
 
-#### Public
+!!! example "Example: Database that is hidden but certain views are visible"
+
+    Database *Airquality* has the settings to hide all data and schema by default.
+
+    * Table `sensor` inherits the settings from the database by default and therefore is also **hidden**. Nobody can
+      read/write to this database by default. Only designated users that the database owner allows to read/write can do
+      so.
+    * View `v_sensor` inherits the settings from the database by default and therefore is also **hidden**. The database
+      owner wants the data to be visible to the public (anonymously), so he changes the settings to data=visible,
+      schema=hidden. Now everybody can see the data but not the table(s) that contain the data.
+
+#### Visible
 
 !!! info "Possible use-case: data publication supplement to an open-access publication"
 
-Where the database's data and metadata is set to be *visible*. This means everything in the database (tables, views,
-subsets) are visible by anyone from the public.
+Where the resource's data and schema is set to be visible.
 
-#### Private
+#### Data-only
 
 !!! info "Possible use-case: private sensor measurements with timed embargo"
 
-Where the database's data set to be *hidden* but the schema to be *visible*. This means everything in the database
-(tables, views, subsets) are by default not visible by anyone from the public. You can however make specific views that
-join tables and/or filter certain columns and apply a 14-day delay-embargo.
+Where the resource's schema visibility is hidden but the data is visible.
 
-<figure markdown>
-![Mirroring statistical properties in Metadata Database and Search Database](../images/private-embargo.svg)
-<figcaption>Figure 1: Public view that joins two private tables and applies a time-embargo</figcaption>
-</figure>
+#### Schema-only
+
+!!! info "Possible use-case: publish data for reviewers before the final publication"
+
+Where the resource's data visibility is hidden but the schema is visible.
 
 #### Draft
 
-!!! info "Possible use-case: project data storage before publication"
\ No newline at end of file
+!!! info "Possible use-case: project data storage before publication"
+
+Where the resource's data and schema visibility is hidden. It will not be findable even in the search.
\ No newline at end of file
diff --git a/.docs/images/architecture.drawio b/.docs/images/architecture.drawio
index 71536a321290f6c8cb39d147529a8b00fb458eed..b1aed4cb4035dfa1cbc08818c44ca5d7fac5a803 100644
--- a/.docs/images/architecture.drawio
+++ b/.docs/images/architecture.drawio
@@ -1,4 +1,4 @@
-<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/25.0.2 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="25.0.2" pages="9">
+<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.0.9 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="26.0.9" pages="9">
   <diagram id="mvBsv1rP8O80Qe3yGnn_" name="docker-compose">
     <mxGraphModel dx="683" dy="391" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
       <root>
@@ -1109,47 +1109,10 @@
     </mxGraphModel>
   </diagram>
   <diagram id="7HywRA3nQAgvNxZjCRq2" name="private-embargo">
-    <mxGraphModel dx="985" dy="394" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
+    <mxGraphModel dx="1434" dy="822" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
       <root>
         <mxCell id="0" />
         <mxCell id="1" parent="0" />
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0;entryDx=0;entryDy=0;curved=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-1" target="n6nk3BLY6128t3IB6Ma7-5">
-          <mxGeometry relative="1" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-11" value="&lt;span style=&quot;text-wrap: wrap; background-color: rgb(251, 251, 251);&quot;&gt;value,loc_id&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=8;" vertex="1" connectable="0" parent="n6nk3BLY6128t3IB6Ma7-8">
-          <mxGeometry x="0.0303" relative="1" as="geometry">
-            <mxPoint as="offset" />
-          </mxGeometry>
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-1" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
-          <mxGeometry x="250" y="170" width="80" height="80" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-2" value="&lt;b&gt;table&lt;/b&gt;: sensor (private)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-          <mxGeometry x="227.5" y="150" width="125" height="20" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;curved=1;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-3" target="n6nk3BLY6128t3IB6Ma7-5">
-          <mxGeometry relative="1" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-12" value="id,name,lat,lng" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=8;" vertex="1" connectable="0" parent="n6nk3BLY6128t3IB6Ma7-9">
-          <mxGeometry x="0.1455" relative="1" as="geometry">
-            <mxPoint as="offset" />
-          </mxGeometry>
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-3" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
-          <mxGeometry x="430" y="170" width="80" height="80" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-4" value="&lt;b&gt;table&lt;/b&gt;: location (private)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-          <mxGeometry x="405" y="150" width="130" height="20" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-5" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=8;" vertex="1" parent="1">
-          <mxGeometry x="340" y="290" width="80" height="80" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-6" value="&lt;b&gt;view&lt;/b&gt;: validated_sensor (public)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-          <mxGeometry x="290" y="370" width="180" height="20" as="geometry" />
-        </mxCell>
-        <mxCell id="n6nk3BLY6128t3IB6Ma7-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-4" target="n6nk3BLY6128t3IB6Ma7-4">
-          <mxGeometry relative="1" as="geometry" />
-        </mxCell>
       </root>
     </mxGraphModel>
   </diagram>
diff --git a/.docs/index.md b/.docs/index.md
index 64b807cae27ed8db6f928633bbd1f957887b3b0c..d86224726f28fb78b3022601e02b00859a5ecc7d 100644
--- a/.docs/index.md
+++ b/.docs/index.md
@@ -14,7 +14,7 @@ author: Martin Weise
 ![Maintainability Rating](./images/maintainability.svg)
 ![Security Rating](./images/security.svg)
 
-Documentation for version: [v1.6.2](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases).
+Documentation for version: [v1.6.3](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases).
 
 DBRepo is a repository for data in databases that are used from the beginning until the end of a research 
 project supporting data evolution, -citation and -versioning. It implements the query store of the 
diff --git a/.docs/installation.md b/.docs/installation.md
index ee0d9b88faa47ca33f74c12c5cf63200e7ff7ffc..1c6db304ccf3d760c44e56b7d49aef49d76330ff 100644
--- a/.docs/installation.md
+++ b/.docs/installation.md
@@ -31,11 +31,11 @@ settings.
 - min. 200GB free SSD storage
 
 Since DBRepo is intended to be a publicly available repository, an optional fixed/static IP-address with optional
-SSL/TLS certificate is recommended. Follow the [secure install](#secure-install) guide.
+SSL/TLS certificate is recommended. Follow the [secure installation](#secure-installation) guide.
 
 ## Secure Installation
 
-Execute the install script to download only the environment and save it to `dist`.
+Execute the installation script to download only the environment and save it to `dist`.
 
 ```shell
 curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.6/install.sh | DOWNLOAD_ONLY=1 bash
@@ -50,6 +50,8 @@ Update the rest of the default secrets in the `.env` file to secure passwords. Y
 `openssl rand -hex 16`. Set `auth_ldap.dn_lookup_bind.password` in `dist/rabbitmq.conf` to the value of
 `SYSTEM_PASSWORD`.
 
+Only set the `BASE_URL` environment variable in `.env` when your hostname is **not** `localhost`.
+
 ### Runtime Configuration
 
 The [Auth Service](../api/auth-service) can be configured easily when DBRepo is running. Start DBRepo temporarily:
diff --git a/.docs/kubernetes.md b/.docs/kubernetes.md
index 60f87eb6d4e8047ee0b767e08a6ccecda64a6a81..170bc863f58206778bf4488c48f322e6ad801996 100644
--- a/.docs/kubernetes.md
+++ b/.docs/kubernetes.md
@@ -14,7 +14,7 @@ helm upgrade --install dbrepo \
   -n dbrepo \
   "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" \
   --values ./values.yaml \
-  --version "1.6.2" \
+  --version "1.6.3" \
   --create-namespace \
   --cleanup-on-fail
 ```
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3661711509265e6d7889e13a24dd2a2e24f7a689..85e5d640bbce875195f6c560d3e60e0d210f650e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,8 +10,8 @@ variables:
   SONARQUBE_VERSION: "10.0"
   BUN_VERSION: "1.1.40"
   DOC_VERSION: "1.6"
-  APP_VERSION: "1.6.2"
-  CHART_VERSION: "1.6.2"
+  APP_VERSION: "1.6.3"
+  CHART_VERSION: "1.6.3"
   CACHE_FALLBACK_KEY: "${CI_DEFAULT_BRANCH}"
   # This will supress any download for dependencies and plugins or upload messages which would clutter the console log.
   # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work.
diff --git a/.gitlab/agents/dev/values.yaml b/.gitlab/agents/dev/values.yaml
index aa241d7f0eef507e104fb2ea49c9c01e37390ed5..5841a5e97bd5d9f9ddde4d13a2b74623a91cf4fb 100644
--- a/.gitlab/agents/dev/values.yaml
+++ b/.gitlab/agents/dev/values.yaml
@@ -26,6 +26,9 @@ authservice:
   client:
     id: dbrepo-client
     secret: MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG
+  setupJob:
+    image:
+      name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.3
   persistence:
     enabled: true
 
@@ -33,6 +36,7 @@ brokerservice:
   enabled: true
   ldap:
     bindpw: b8534187c9adf9618e7bd1c79c7f4639
+
 identityservice:
   enabled: true
   global:
@@ -66,9 +70,13 @@ searchdb:
 
 analyseservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3
 
 metadataservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
   admin:
     email: noreply@example.com
   deletedRecord: permanent
@@ -83,6 +91,8 @@ metadataservice:
 
 dataservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3
   rabbitmq:
     consumer:
       username: admin
@@ -95,9 +105,17 @@ dataservice:
 
 searchservice:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3
+  init:
+    image:
+      name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3
 
 storageservice:
   enabled: true
+  init:
+    image:
+      name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3
 
 uploadservice:
   enabled: true
@@ -113,13 +131,15 @@ metricdb:
 
 ui:
   enabled: true
+  image:
+    name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3
   public:
     api:
       client: https://s155.datalab.tuwien.ac.at
       server: https://s155.datalab.tuwien.ac.at
     title: "Database Repository"
     logo: "https://ec.tuwien.ac.at/~weise/images/DS_white_hiRes.png"
-    icon: "https://ec.tuwien.ac.at/~weise/images/DS-icon_white_hiRes.png"
+    icon: "https://ec.tuwien.ac.at/~weise/images/favicon.ico"
     touch: "https://ec.tuwien.ac.at/~weise/images/DS-icon_white_hiRes.png"
     broker:
       host: s155.datalab.tuwien.ac.at
diff --git a/Makefile b/Makefile
index e5d0dbec5fdf080bc5224e52531b6fc3706bddeb..0dd2ae5e0a756aa713a101ddfff2ff8513222fa4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 .PHONY: all
 
-APP_VERSION ?= 1.6.2
-CHART_VERSION ?= 1.6.2
+APP_VERSION ?= 1.6.3
+CHART_VERSION ?= 1.6.3
 REPOSITORY_URL ?= registry.datalab.tuwien.ac.at/dbrepo
 
 .PHONY: all
diff --git a/dbrepo-analyse-service/Pipfile b/dbrepo-analyse-service/Pipfile
index 9c7b7095205c5fce88254ac94439db010a03bef0..22a8e79b3a232b73784971df01dc283b8171388d 100644
--- a/dbrepo-analyse-service/Pipfile
+++ b/dbrepo-analyse-service/Pipfile
@@ -21,7 +21,7 @@ numpy = "*"
 pandas = "*"
 minio = "*"
 pydantic = "*"
-dbrepo = {path = "./lib/dbrepo-1.6.2.tar.gz"}
+dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"}
 opensearch-py = "*"
 
 [dev-packages]
diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock
index f177d904cb25228548dbc3ee5e0bef46919d6698..5d2ace3655c32086fe018e0267ab207a9f1703b6 100644
--- a/dbrepo-analyse-service/Pipfile.lock
+++ b/dbrepo-analyse-service/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "5fbd87c094d93565d64444fc1734d9183e7095d47447d30d6493dfc6bb7e8201"
+            "sha256": "9cc4c161729b642069bbf4ab379c0f4a9122035afcb3ac7b5b1bfc13281f76aa"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -159,11 +159,11 @@
         },
         "attrs": {
             "hashes": [
-                "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff",
-                "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"
+                "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e",
+                "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==24.3.0"
+            "version": "==25.1.0"
         },
         "blinker": {
             "hashes": [
@@ -175,20 +175,20 @@
         },
         "boto3": {
             "hashes": [
-                "sha256:53a5307f6a3526ee2f8590e3c45efa504a3ea4532c1bfe4926c0c19bf188d141",
-                "sha256:f9843a5d06f501d66ada06f5a5417f671823af2cf319e36ceefa1bafaaaaa953"
+                "sha256:7f61c9d0ea64f484a17c1e3115fdf90fd7b17ab6771e07cb4549f42b9fd28fb9",
+                "sha256:ac47215d320b0c2534340db58d6d5284cb1860b7bff172b4dd6eee2dee1d5779"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.8'",
-            "version": "==1.36.3"
+            "version": "==1.36.8"
         },
         "botocore": {
             "hashes": [
-                "sha256:536ab828e6f90dbb000e3702ac45fd76642113ae2db1b7b1373ad24104e89255",
-                "sha256:775b835e979da5c96548ed1a0b798101a145aec3cd46541d62e27dda5a94d7f8"
+                "sha256:59d3fdfbae6d916b046e973bebcbeb70a102f9e570ca86d5ba512f1854b78fc2",
+                "sha256:81c88e5566cf018e1411a68304dc1fb9e4156ca2b50a3a0f0befc274299e67fa"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==1.36.3"
+            "version": "==1.36.8"
         },
         "certifi": {
             "hashes": [
@@ -412,9 +412,9 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:a41ca60353510cbecf8fb647cf2483acb100258743794a16bc8ad6f8e9ea4481"
+                "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d"
             ],
-            "path": "./lib/dbrepo-1.6.2.tar.gz"
+            "path": "./lib/dbrepo-1.6.3.tar.gz"
         },
         "events": {
             "hashes": [
@@ -838,11 +838,11 @@
         },
         "mistune": {
             "hashes": [
-                "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1",
-                "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667"
+                "sha256:02106ac2aa4f66e769debbfa028509a275069dcffce0dfa578edd7b991ee700a",
+                "sha256:e0740d635f515119f7d1feb6f9b192ee60f0cc649f80a8f944f905706a21654c"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==3.1.0"
+            "version": "==3.1.1"
         },
         "multidict": {
             "hashes": [
@@ -1230,12 +1230,12 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff",
-                "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"
+                "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584",
+                "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.8'",
-            "version": "==2.10.5"
+            "version": "==2.10.6"
         },
         "pydantic-core": {
             "hashes": [
@@ -1427,11 +1427,11 @@
         },
         "referencing": {
             "hashes": [
-                "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794",
-                "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade"
+                "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa",
+                "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"
             ],
             "markers": "python_version >= '3.9'",
-            "version": "==0.36.1"
+            "version": "==0.36.2"
         },
         "requests": {
             "hashes": [
@@ -1553,11 +1553,11 @@
         },
         "s3transfer": {
             "hashes": [
-                "sha256:3f25c900a367c8b7f7d8f9c34edc87e300bde424f779dc9f0a8ae4f9df9264f6",
-                "sha256:8fa0aa48177be1f3425176dfe1ab85dcd3d962df603c3dbfc585e6bf857ef0ff"
+                "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f",
+                "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==0.11.1"
+            "version": "==0.11.2"
         },
         "setuptools": {
             "hashes": [
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl
index 24256263e2fb3156ac0eea01079116e4b40e36fd..256d325e8bdbdacd8c967d852c98e39d8d3b9eb9 100644
Binary files a/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl and b/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz
index 2ae1ea50b1610050f5bd5746f7e9596b1c483c9d..ad4d6f9c5590836360d1a919f4be84b5cc5f9ade 100644
Binary files a/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz and b/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1
Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl differ
diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253
Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz differ
diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json
index b48be9a6bdc607bbfe2f7190b3733238f31f29b8..1c703b83750c5aa21d4da06c7895d74211122ae9 100644
--- a/dbrepo-auth-service/dbrepo-realm.json
+++ b/dbrepo-auth-service/dbrepo-realm.json
@@ -27,7 +27,7 @@
   "oauth2DevicePollingInterval" : 5,
   "enabled" : true,
   "sslRequired" : "none",
-  "registrationAllowed" : false,
+  "registrationAllowed" : true,
   "registrationEmailAsUsername" : false,
   "rememberMe" : false,
   "verifyEmail" : true,
@@ -38,6 +38,7 @@
   "bruteForceProtected" : false,
   "permanentLockout" : false,
   "maxTemporaryLockouts" : 0,
+  "bruteForceStrategy" : "MULTIPLE",
   "maxFailureWaitSeconds" : 900,
   "minimumQuickLoginWaitSeconds" : 60,
   "waitIncrementSeconds" : 60,
@@ -1308,8 +1309,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
-      "client.use.lightweight.access.token.enabled" : "true"
+      "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
     "fullScopeAllowed" : true,
@@ -1383,6 +1384,38 @@
     "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : -1,
     "protocolMappers" : [ {
+      "id" : "266edf62-a19a-483b-b594-81428e4af792",
+      "name" : "orcid",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "ORCID",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "orcid",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "1a21798a-38b6-4df5-89f0-86942415246f",
+      "name" : "theme",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "THEME",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "theme",
+        "jsonType.label" : "String"
+      }
+    }, {
       "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
       "name" : "preferred_username",
       "protocol" : "openid-connect",
@@ -1396,18 +1429,66 @@
         "userinfo.token.claim" : "true"
       }
     }, {
-      "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
-      "name" : "aud",
+      "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a",
+      "name" : "affiliation",
       "protocol" : "openid-connect",
-      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "dbrepo",
+        "introspection.token.claim" : "true",
         "userinfo.token.claim" : "true",
+        "user.attribute" : "AFFILIATION",
         "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
-        "claim.name" : "aud",
-        "access.tokenResponse.claim" : "false"
+        "claim.name" : "affiliation",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88",
+      "name" : "language",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "LANGUAGE",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "language",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
       }
     }, {
       "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc",
@@ -1424,9 +1505,26 @@
         "access.token.claim" : "true",
         "claim.name" : "uid"
       }
+    }, {
+      "id" : "c304ed2f-5952-4772-838d-91998a45f154",
+      "name" : "aud",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "claim.value" : "account",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "jsonType.label" : "String",
+        "access.tokenResponse.claim" : "false"
+      }
     } ],
-    "defaultClientScopes" : [ "roles", "attributes", "basic" ],
-    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+    "defaultClientScopes" : [ "roles", "basic" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
   }, {
     "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
     "clientId" : "rabbitmq-client",
@@ -1471,12 +1569,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "false",
         "user.attribute" : "username",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "client_id",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "false"
       }
     }, {
       "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
@@ -1485,11 +1583,11 @@
       "protocolMapper" : "oidc-hardcoded-claim-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "rabbitmq",
-        "userinfo.token.claim" : "false",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "aud",
+        "claim.value" : "rabbitmq",
+        "userinfo.token.claim" : "false",
         "access.tokenResponse.claim" : "false"
       }
     } ],
@@ -1548,8 +1646,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
       "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -1562,12 +1660,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ],
     "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
@@ -1591,8 +1689,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${emailScopeConsentText}"
+      "consent.screen.text" : "${emailScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
@@ -1601,12 +1699,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "emailVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
@@ -1615,12 +1713,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "email",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1630,8 +1728,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${profileScopeConsentText}"
+      "consent.screen.text" : "${profileScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
@@ -1640,12 +1738,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "preferred_username",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
@@ -1654,12 +1752,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "gender",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "gender",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
@@ -1668,12 +1766,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "birthdate",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "birthdate",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
@@ -1693,12 +1791,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "profile",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "profile",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
@@ -1707,12 +1805,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "updatedAt",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "updated_at",
-        "jsonType.label" : "long"
+        "jsonType.label" : "long",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "841ea785-26ab-429a-a420-09ce3948924d",
@@ -1721,12 +1819,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "lastName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "family_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
@@ -1735,12 +1833,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "website",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "website",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "475f071d-5149-4379-b928-76482f5f519c",
@@ -1749,12 +1847,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "zoneinfo",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "zoneinfo",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
@@ -1763,12 +1861,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "middleName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "middle_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
@@ -1777,12 +1875,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "picture",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "picture",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
@@ -1791,12 +1889,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
@@ -1805,12 +1903,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "firstName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "given_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
@@ -1819,12 +1917,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "nickname",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "nickname",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1858,12 +1956,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "upn",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1905,8 +2003,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${phoneScopeConsentText}"
+      "consent.screen.text" : "${phoneScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
@@ -1915,12 +2013,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumber",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
@@ -1929,12 +2027,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumberVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1944,8 +2042,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "false",
-      "consent.screen.text" : ""
+      "consent.screen.text" : "",
+      "display.on.consent.screen" : "false"
     },
     "protocolMappers" : [ {
       "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
@@ -2025,6 +2123,61 @@
       "gui.order" : "",
       "consent.screen.text" : ""
     }
+  }, {
+    "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6",
+    "name" : "service_account",
+    "description" : "Specific scope for a client enabled for service accounts",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512",
+      "name" : "Client IP Address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientAddress",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientAddress",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a",
+      "name" : "Client Host",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientHost",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientHost",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae",
+      "name" : "Client ID",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "client_id",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    } ]
   }, {
     "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
     "name" : "offline_access",
@@ -2041,8 +2194,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${addressScopeConsentText}"
+      "consent.screen.text" : "${addressScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
@@ -2115,8 +2268,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${rolesScopeConsentText}"
+      "consent.screen.text" : "${rolesScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
@@ -2132,11 +2285,15 @@
       "protocolMapper" : "oidc-usermodel-realm-role-mapper",
       "consentRequired" : false,
       "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "false",
+        "multivalued" : "true",
         "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "realm_access.roles",
-        "jsonType.label" : "String",
-        "multivalued" : "true"
+        "jsonType.label" : "String"
       }
     }, {
       "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
@@ -2166,8 +2323,12 @@
     "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
   },
   "smtpServer" : { },
+  "loginTheme" : "keycloak.v2",
+  "accountTheme" : "",
+  "adminTheme" : "",
+  "emailTheme" : "",
   "eventsEnabled" : false,
-  "eventsListeners" : [ "jboss-logging" ],
+  "eventsListeners" : [ "create-event-listener", "jboss-logging" ],
   "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
   "adminEventsEnabled" : false,
   "adminEventsDetailsEnabled" : false,
@@ -2215,7 +2376,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2241,7 +2402,15 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+      }
+    } ],
+    "org.keycloak.userprofile.UserProfileProvider" : [ {
+      "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
+      "providerId" : "declarative-user-profile",
+      "subComponents" : { },
+      "config" : {
+        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
       }
     } ],
     "org.keycloak.storage.UserStorageProvider" : [ {
@@ -2257,8 +2426,8 @@
           "config" : {
             "ldap.attribute" : [ "createTimestamp" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "read.only" : [ "true" ],
             "always.read.value.from.ldap" : [ "true" ],
+            "read.only" : [ "true" ],
             "user.model.attribute" : [ "createTimestamp" ]
           }
         }, {
@@ -2269,8 +2438,8 @@
           "config" : {
             "ldap.attribute" : [ "sn" ],
             "is.mandatory.in.ldap" : [ "true" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "false" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "lastName" ]
           }
         }, {
@@ -2293,8 +2462,8 @@
           "config" : {
             "ldap.attribute" : [ "mail" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "false" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "email" ]
           }
         }, {
@@ -2303,19 +2472,19 @@
           "providerId" : "group-ldap-mapper",
           "subComponents" : { },
           "config" : {
+            "mode" : [ "LDAP_ONLY" ],
             "membership.attribute.type" : [ "DN" ],
+            "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
             "group.name.ldap.attribute" : [ "cn" ],
-            "preserve.group.inheritance" : [ "false" ],
             "membership.user.ldap.attribute" : [ "uid" ],
-            "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
-            "mode" : [ "LDAP_ONLY" ],
-            "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
-            "membership.ldap.attribute" : [ "member" ],
             "ignore.missing.groups" : [ "false" ],
+            "preserve.group.inheritance" : [ "false" ],
+            "membership.ldap.attribute" : [ "member" ],
             "memberof.ldap.attribute" : [ "memberOf" ],
             "group.object.classes" : [ "groupOfNames" ],
-            "drop.non.existing.groups.during.sync" : [ "false" ],
-            "groups.path" : [ "/" ]
+            "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
+            "groups.path" : [ "/" ],
+            "drop.non.existing.groups.during.sync" : [ "false" ]
           }
         }, {
           "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb",
@@ -2339,15 +2508,15 @@
             "is.mandatory.in.ldap" : [ "true" ],
             "attribute.force.default" : [ "false" ],
             "is.binary.attribute" : [ "false" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "false" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "username" ]
           }
         } ]
       },
       "config" : {
-        "pagination" : [ "false" ],
         "fullSyncPeriod" : [ "-1" ],
+        "pagination" : [ "false" ],
         "startTls" : [ "false" ],
         "connectionPooling" : [ "true" ],
         "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ],
@@ -2355,15 +2524,15 @@
         "useKerberosForPasswordAuthentication" : [ "false" ],
         "importEnabled" : [ "true" ],
         "enabled" : [ "true" ],
+        "bindCredential" : [ "admin" ],
         "changedSyncPeriod" : [ "-1" ],
-        "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
         "usernameLDAPAttribute" : [ "uid" ],
-        "bindCredential" : [ "admin" ],
+        "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
         "lastSync" : [ "1719252666" ],
         "vendor" : [ "other" ],
         "uuidLDAPAttribute" : [ "entryUUID" ],
-        "connectionUrl" : [ "ldap://identity-service:1389" ],
         "allowKerberosAuthentication" : [ "false" ],
+        "connectionUrl" : [ "ldap://identity-service:1389" ],
         "syncRegistrations" : [ "true" ],
         "authType" : [ "simple" ],
         "useTruststoreSpi" : [ "always" ],
@@ -2375,14 +2544,6 @@
         "validatePasswordPolicy" : [ "false" ]
       }
     } ],
-    "org.keycloak.userprofile.UserProfileProvider" : [ {
-      "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
-      "providerId" : "declarative-user-profile",
-      "subComponents" : { },
-      "config" : {
-        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
-      }
-    } ],
     "org.keycloak.keys.KeyProvider" : [ {
       "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51",
       "name" : "rsa-enc-generated",
@@ -2995,10 +3156,12 @@
     "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
     "parRequestUriLifespan" : "60",
     "clientSessionMaxLifespan" : "0",
+    "organizationsEnabled" : "false",
     "shortVerificationUri" : ""
   },
-  "keycloakVersion" : "24.0.5",
+  "keycloakVersion" : "26.0.4",
   "userManagedAccessAllowed" : false,
+  "organizationsEnabled" : false,
   "clientProfiles" : {
     "profiles" : [ ]
   },
diff --git a/dbrepo-auth-service/init/Pipfile.lock b/dbrepo-auth-service/init/Pipfile.lock
index c8224a7844942ed36a6fef30185dc094f516378d..57631a05559948613a5c9a63b37463c95a48da9a 100644
--- a/dbrepo-auth-service/init/Pipfile.lock
+++ b/dbrepo-auth-service/init/Pipfile.lock
@@ -18,11 +18,11 @@
     "default": {
         "certifi": {
             "hashes": [
-                "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
-                "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
+                "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
+                "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==2024.12.14"
+            "version": "==2025.1.31"
         },
         "charset-normalizer": {
             "hashes": [
@@ -175,11 +175,11 @@
     "develop": {
         "certifi": {
             "hashes": [
-                "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
-                "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
+                "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
+                "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"
             ],
             "markers": "python_version >= '3.6'",
-            "version": "==2024.12.14"
+            "version": "==2025.1.31"
         },
         "charset-normalizer": {
             "hashes": [
diff --git a/dbrepo-auth-service/init/app.py b/dbrepo-auth-service/init/app.py
index 270e959fecb30c9f200ba96c8186357cb94599b9..5e42003a192d4b6536ccd8f6c6ccc1be9dcedd6d 100644
--- a/dbrepo-auth-service/init/app.py
+++ b/dbrepo-auth-service/init/app.py
@@ -7,7 +7,7 @@ endpoint = os.getenv('AUTH_SERVICE_ENDPOINT', 'http://localhost:8080')
 system_username = os.getenv('SYSTEM_USERNAME', 'admin')
 
 
-def fetch() -> str:
+def fetch() -> (str, str):
     print(f'Fetching user id of internal user with username: {system_username}')
     response = post(url=f'{endpoint}/realms/master/protocol/openid-connect/token', data=dict({
         'username': os.getenv('AUTH_SERVICE_ADMIN', 'admin'),
@@ -25,7 +25,8 @@ def fetch() -> str:
     if response.status_code != 200 or len(response.json()) != 1:
         raise FileNotFoundError(f'Failed to obtain user')
     ldap_user = response.json()[0]
-    print(f'Successfully fetched user id: {ldap_user["id"]}')
+    user_id = ldap_user["id"]
+    print(f'Successfully fetched user id: {user_id}')
     if 'attributes' not in ldap_user or ldap_user['attributes'] is None:
         raise ModuleNotFoundError(f'Failed to obtain user attributes: {ldap_user}')
     ldap_user_attrs = ldap_user['attributes']
@@ -35,10 +36,10 @@ def fetch() -> str:
         raise EnvironmentError(f'Failed to obtain ldap id: wrong length {len(ldap_user_attrs["LDAP_ID"])} != 1')
     ldap_user_id = ldap_user_attrs['LDAP_ID'][0]
     print(f'Successfully fetched ldap user id: {ldap_user_id}')
-    return ldap_user_id
+    return (ldap_user_id, user_id)
 
 
-def save(user_id: str) -> None:
+def save(user_id: str, keycloak_id: str) -> None:
     conn = mariadb.connect(user=os.getenv('METADATA_USERNAME', 'root'),
                            password=os.getenv('METADATA_DB_PASSWORD', 'dbrepo'),
                            host="metadata-db",
@@ -46,12 +47,13 @@ def save(user_id: str) -> None:
                            database=os.getenv('METADATA_DB', 'dbrepo'))
     cursor = conn.cursor()
     cursor.execute(
-        "INSERT IGNORE INTO `mdb_users` (`id`, `username`, `email`, `mariadb_password`, `is_internal`) VALUES (?, ?, LEFT(UUID(), 20), PASSWORD(LEFT(UUID(), 20)), true)",
-        (user_id, system_username))
+        "INSERT IGNORE INTO `mdb_users` (`id`, `keycloak_id`, `username`, `mariadb_password`, `is_internal`) VALUES (?, ?, ?, PASSWORD(LEFT(UUID(), 20)), true)",
+        (user_id, keycloak_id, system_username))
     conn.commit()
     conn.close()
 
 
 if __name__ == '__main__':
-    save(fetch())
+    user_id, keycloak_id = fetch()
+    save(user_id, keycloak_id)
     print(f'Successfully inserted user')
diff --git a/dbrepo-auth-service/init/test/test_unit_app.py b/dbrepo-auth-service/init/test/test_unit_app.py
index 624b7d8d53e7393d2077c214278bdb98f32297ba..af6aed379a3780157718d760bdabd79475e8d249 100644
--- a/dbrepo-auth-service/init/test/test_unit_app.py
+++ b/dbrepo-auth-service/init/test/test_unit_app.py
@@ -16,38 +16,6 @@ class AppUnitTest(unittest.TestCase):
         "session_state": "ae64d2bd-3225-4e05-9943-2bb91fb8fe52",
         "scope": "profile email"
     }
-    user_res = [
-        {"id": "5b516520-67cb-4aa0-86a6-d12f8b8f1a20",
-         "username": "admin",
-         "firstName": "User1",
-         "lastName": "Bar1",
-         "emailVerified": False,
-         "attributes": {"LDAP_ENTRY_DN": ["cn=admin,ou=users,dc=dbrepo,dc=at"],
-                        "createTimestamp": ["20250120141013Z"],
-                        "modifyTimestamp": ["20250120141013Z"],
-                        "LDAP_ID": ["02b6e096-6b84-103f-81f6-1f6da137f2bb"]},
-         "createdTimestamp": 1737382606939,
-         "enabled": True,
-         "totp": False,
-         "federationLink": "c109d473-5ce1-4032-af7b-02e5442f5c07",
-         "disableableCredentialTypes": [],
-         "requiredActions": [],
-         "notBefore": 0,
-         "access": {"manageGroupMembership": True,
-                    "view": True,
-                    "mapRoles": True,
-                    "impersonate": True,
-                    "manage": True}}]
-
-    def test_fetch_succeeds(self):
-        with requests_mock.Mocker() as mock:
-            # mock
-            mock.post(f'{endpoint}/realms/master/protocol/openid-connect/token', json=self.token_res, status_code=200)
-            mock.get(f'{endpoint}/admin/realms/dbrepo/users/?username=admin', json=self.user_res, status_code=200)
-
-            # test
-            user_id = fetch()
-            self.assertEqual("02b6e096-6b84-103f-81f6-1f6da137f2bb", user_id)
 
     def test_fetch_token_bad_request_fails(self):
         with requests_mock.Mocker() as mock:
diff --git a/dbrepo-auth-service/listeners/.gitignore b/dbrepo-auth-service/listeners/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..5d6e1ae3b181727bbd28cdb0107283899c3a0fd2
--- /dev/null
+++ b/dbrepo-auth-service/listeners/.gitignore
@@ -0,0 +1,30 @@
+### IntelliJ IDEA ###
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+target/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/pom.xml b/dbrepo-auth-service/listeners/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e70201b96ac3d853a0274c7f06499d336f1c27cf
--- /dev/null
+++ b/dbrepo-auth-service/listeners/pom.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-parent</artifactId>
+        <version>24.0.5</version>
+    </parent>
+
+    <groupId>at.tuwien</groupId>
+    <artifactId>create-event-listener</artifactId>
+    <name>dbrepo-auth-service</name>
+    <version>24.0.5</version>
+
+    <description>Create event listener</description>
+
+    <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url>
+    <developers>
+        <developer>
+            <name>Martin Weise</name>
+            <email>martin.weise@tuwien.ac.at</email>
+            <organization>TU Wien</organization>
+        </developer>
+    </developers>
+
+    <properties>
+        <java.version>17</java.version>
+        <maven.version>3.9.8</maven.version>
+        <maven.compiler.source>${java.version}</maven.compiler.source>
+        <maven.compiler.target>${java.version}</maven.compiler.target>
+        <maven.compiler.release>${java.version}</maven.compiler.release>
+        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
+        <testcontainers.version>1.19.1</testcontainers.version>
+        <keycloak-testcontainer.version>3.2.0</keycloak-testcontainer.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-saml-core-public</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ws.rs</groupId>
+            <artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
+        </dependency>
+        <!-- Tests -->
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>${testcontainers.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.dasniko</groupId>
+            <artifactId>testcontainers-keycloak</artifactId>
+            <version>${keycloak-testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>create-event-listener</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.version}</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java
new file mode 100644
index 0000000000000000000000000000000000000000..769ec49097223e5fd49f76d855d9acef1cfbe35c
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java
@@ -0,0 +1,65 @@
+package at.tuwien;
+
+import org.jboss.logging.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Base64;
+
+public class Client {
+    private static final Logger log = Logger.getLogger(Client.class);
+
+    public static void postService(String data) throws IOException {
+        try {
+            final String urlString = System.getenv("METADATA_SERVICE_ENDPOINT");
+            log.debugf("METADATA_SERVICE_ENDPOINT: %s", urlString);
+            if (urlString == null || urlString.isEmpty()) {
+                throw new IllegalArgumentException("Environment variable METADATA_SERVICE_ENDPOINT is not set or is empty.");
+            }
+            final String systemUsername = System.getenv("SYSTEM_USERNAME");
+            if (systemUsername == null || systemUsername.isEmpty()) {
+                throw new IllegalArgumentException("Environment variable SYSTEM_USERNAME is not set or is empty.");
+            }
+            log.debugf("SYSTEM_USERNAME: %s", systemUsername);
+            final String systemPassword = System.getenv("SYSTEM_PASSWORD");
+            if (systemPassword == null || systemPassword.isEmpty()) {
+                throw new IllegalArgumentException("Environment variable SYSTEM_PASSWORD is not set or is empty.");
+            }
+
+            URL url = URI.create(urlString).toURL();
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setDoOutput(true);
+            conn.setRequestMethod("POST");
+            final String token = systemUsername + ":" + systemPassword;
+            conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(token.getBytes(
+                    Charset.defaultCharset())));
+            conn.setRequestProperty("Content-Type", "application/json; utf-8");
+
+            OutputStream os = conn.getOutputStream();
+            os.write(data.getBytes());
+            os.flush();
+
+            final int responseCode = conn.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_CREATED && responseCode != HttpURLConnection.HTTP_OK) {
+                throw new RuntimeException("Failed : HTTP error code : " + responseCode);
+            }
+
+            final BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+            String output;
+            log.debugf("Output from Server .... \n");
+            while ((output = br.readLine()) != null) {
+                System.out.println(output);
+                log.debugf("Input from Server: %s", output);
+            }
+            conn.disconnect();
+        } catch (IOException e) {
+            throw new IOException("Failed to post service: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b5d9221a7beb49385e129f6ccb3fff0aed73002
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java
@@ -0,0 +1,139 @@
+package at.tuwien;
+
+import org.jboss.logging.Logger;
+import org.keycloak.events.Event;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.EventType;
+import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RealmProvider;
+import org.keycloak.models.UserModel;
+
+import java.util.StringJoiner;
+
+public class CreateEventListenerProvider implements EventListenerProvider {
+
+    private static final Logger log = Logger.getLogger(CreateEventListenerProvider.class);
+
+    private final KeycloakSession session;
+    private final RealmProvider model;
+
+    public CreateEventListenerProvider(KeycloakSession session) {
+        this.session = session;
+        this.model = session.realms();
+    }
+
+    @Override
+    public void onEvent(Event event) {
+
+        log.debugf("New %s Event", event.getType());
+        log.debugf("onEvent-> %s", toString(event));
+
+        if (EventType.REGISTER.equals(event.getType())) {
+
+            event.getDetails().forEach((key, value) -> log.debugf("%s : %s", key, value));
+
+            RealmModel realm = this.model.getRealm(event.getRealmId());
+            UserModel user = this.session.users().getUserById(realm, event.getUserId());
+            sendUserData(user);
+        }
+
+    }
+
+    @Override
+    public void onEvent(AdminEvent adminEvent, boolean b) {
+        log.debug("onEvent(AdminEvent)");
+        log.debugf("Resource path: %s", adminEvent.getResourcePath());
+        log.debugf("Resource type: %s", adminEvent.getResourceType());
+        log.debugf("Operation type: %s", adminEvent.getOperationType());
+        log.debugf("AdminEvent.toString(): %s", toString(adminEvent));
+        if (ResourceType.USER.equals(adminEvent.getResourceType())
+                && OperationType.CREATE.equals(adminEvent.getOperationType())) {
+            RealmModel realm = this.model.getRealm(adminEvent.getRealmId());
+            UserModel user = this.session.users().getUserById(realm, adminEvent.getResourcePath().substring(6));
+
+            sendUserData(user);
+        }
+    }
+
+    private void sendUserData(UserModel user) {
+        final String userData = "{" +
+                quoteAttr("id", user.getId()) + ", " +
+                quoteAttr("username", user.getUsername()) + ", " +
+                quoteAttr("email", user.getEmail()) + ", " +
+                quoteAttr("ldap_id", user.getFirstAttribute("LDAP_ID")) + ", " +
+                quoteAttr("given_name", user.getFirstName()) + ", " +
+                quoteAttr("family_name", user.getLastName()) +
+                "}";
+        try {
+            log.debugf("create new user in API: %s", userData);
+            Client.postService(userData);
+        } catch (Exception e) {
+            log.errorf("Failed to call API: %s", e);
+        }
+    }
+
+    private static String quoteAttr(String key, String value) {
+        if (value == null || value.isBlank() || value.isEmpty() || value.contentEquals(" ")) {
+            return "\"" + key + "\": null";
+        }
+        return "\"" + key + "\": \"" + value + "\"";
+    }
+
+    @Override
+    public void close() {
+    }
+
+    private String toString(Event event) {
+        final StringJoiner joiner = new StringJoiner(", ");
+        joiner.add("type=" + event.getType())
+                .add("realmId=" + event.getRealmId())
+                .add("clientId=" + event.getClientId())
+                .add("userId=" + event.getUserId())
+                .add("ipAddress=" + event.getIpAddress());
+        if (event.getError() != null) {
+            joiner.add("error=" + event.getError());
+        }
+        if (event.getDetails() != null) {
+            event.getDetails().forEach((key, value) -> {
+                if (value == null || !value.contains(" ")) {
+                    joiner.add(key + "=" + value);
+                } else {
+                    joiner.add(key + "='" + value + "'");
+                }
+            });
+        }
+        return joiner.toString();
+    }
+
+    private String toString(AdminEvent event) {
+        RealmModel realm = this.model.getRealm(event.getRealmId());
+        UserModel newRegisteredUser = this.session.users().getUserById(realm, event.getAuthDetails().getUserId());
+
+        StringJoiner joiner = new StringJoiner(", ");
+
+        joiner.add("operationType=" + event.getOperationType())
+                .add("realmId=" + event.getAuthDetails().getRealmId())
+                .add("clientId=" + event.getAuthDetails().getClientId())
+                .add("userId=" + event.getAuthDetails().getUserId());
+
+        if (newRegisteredUser != null) {
+            joiner.add("email=" + newRegisteredUser.getEmail())
+                    .add("username=" + newRegisteredUser.getUsername())
+                    .add("firstName=" + newRegisteredUser.getFirstName())
+                    .add("lastName=" + newRegisteredUser.getLastName());
+        }
+
+        joiner.add("ipAddress=" + event.getAuthDetails().getIpAddress())
+                .add("resourcePath=" + event.getResourcePath());
+
+        if (event.getError() != null) {
+            joiner.add("error=" + event.getError());
+        }
+
+        return joiner.toString();
+    }
+}
diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..61477ffa33169504a3368d11d0750c9c1404e160
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java
@@ -0,0 +1,36 @@
+package at.tuwien;
+
+import org.keycloak.Config;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.EventListenerProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+public class CreateEventListenerProviderFactory implements EventListenerProviderFactory {
+
+    @Override
+    public EventListenerProvider create(KeycloakSession keycloakSession) {
+        return new CreateEventListenerProvider(keycloakSession);
+    }
+
+    @Override
+    public void init(Config.Scope scope) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory keycloakSessionFactory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "create-event-listener";
+    }
+
+}
diff --git a/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml  b/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml 
new file mode 100644
index 0000000000000000000000000000000000000000..c0330ba082479a3bd9d0caf86508b5067251ed84
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml 	
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <module name="org.keycloak.keycloak-services" />
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory b/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory
new file mode 100644
index 0000000000000000000000000000000000000000..df3c5521f0958fed5fadb4f006d8ee6eb50f97c2
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory
@@ -0,0 +1 @@
+at.tuwien.CreateEventListenerProviderFactory
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java b/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3d6ee94ccd764d16d589b33b51d501e2a2a3d82
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java
@@ -0,0 +1,18 @@
+package at.tuwien;
+
+import dasniko.testcontainers.keycloak.KeycloakContainer;
+import org.testcontainers.images.PullPolicy;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class EventListenerIntegrationTest {
+
+    @Container
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0")
+            .withImagePullPolicy(PullPolicy.alwaysPull())
+            .withAdminUsername("admin")
+            .withAdminPassword("admin")
+            .withRealmImportFile("dbrepo-realm.json")
+            .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false");
+}
diff --git a/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json b/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json
new file mode 100644
index 0000000000000000000000000000000000000000..56f2003e961a14d09bcd56832437f915cae04dea
--- /dev/null
+++ b/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json
@@ -0,0 +1,2798 @@
+{
+  "id" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+  "realm" : "dbrepo",
+  "notBefore" : 0,
+  "defaultSignatureAlgorithm" : "RS256",
+  "revokeRefreshToken" : false,
+  "refreshTokenMaxReuse" : 1,
+  "accessTokenLifespan" : 900,
+  "accessTokenLifespanForImplicitFlow" : 900,
+  "ssoSessionIdleTimeout" : 864000,
+  "ssoSessionMaxLifespan" : 2592000,
+  "ssoSessionIdleTimeoutRememberMe" : 0,
+  "ssoSessionMaxLifespanRememberMe" : 0,
+  "offlineSessionIdleTimeout" : 2592000,
+  "offlineSessionMaxLifespanEnabled" : false,
+  "offlineSessionMaxLifespan" : 5184000,
+  "clientSessionIdleTimeout" : 0,
+  "clientSessionMaxLifespan" : 0,
+  "clientOfflineSessionIdleTimeout" : 0,
+  "clientOfflineSessionMaxLifespan" : 0,
+  "accessCodeLifespan" : 60,
+  "accessCodeLifespanUserAction" : 300,
+  "accessCodeLifespanLogin" : 1800,
+  "actionTokenGeneratedByAdminLifespan" : 43200,
+  "actionTokenGeneratedByUserLifespan" : 1800,
+  "oauth2DeviceCodeLifespan" : 600,
+  "oauth2DevicePollingInterval" : 5,
+  "enabled" : true,
+  "sslRequired" : "none",
+  "registrationAllowed" : false,
+  "registrationEmailAsUsername" : false,
+  "rememberMe" : false,
+  "verifyEmail" : true,
+  "loginWithEmailAllowed" : false,
+  "duplicateEmailsAllowed" : false,
+  "resetPasswordAllowed" : false,
+  "editUsernameAllowed" : false,
+  "bruteForceProtected" : false,
+  "permanentLockout" : false,
+  "maxTemporaryLockouts" : 0,
+  "maxFailureWaitSeconds" : 900,
+  "minimumQuickLoginWaitSeconds" : 60,
+  "waitIncrementSeconds" : 60,
+  "quickLoginCheckMilliSeconds" : 1000,
+  "maxDeltaTimeSeconds" : 43200,
+  "failureFactor" : 30,
+  "roles" : {
+    "realm" : [ {
+      "id" : "48f38342-1e3f-427a-995d-c436eaee65cb",
+      "name" : "default-user-handling",
+      "description" : "${default-user-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-user-theme", "modify-user-information" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "9bb4a8dc-28e0-4645-b62f-cc94425f0cb0",
+      "name" : "default-maintenance-handling",
+      "description" : "${default-maintenance-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-maintenance-message", "find-maintenance-message", "update-maintenance-message", "delete-maintenance-message", "list-maintenance-messages" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7ee1c424-11b0-46a9-b0ed-725e9b7fc40c",
+      "name" : "default-system-roles",
+      "description" : "${default-system-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "143ba359-5fa2-451e-8296-43ecf20bb251",
+      "name" : "update-semantic-concept",
+      "description" : "${update-semantic-concept}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "5136d7a3-e3f0-4585-bacd-15cb8a56095c",
+      "name" : "escalated-container-handling",
+      "description" : "${escalated-container-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-container", "delete-container" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b0bc8649-7d84-4dd3-84f0-7f174425babe",
+      "name" : "list-tables",
+      "description" : "${list-tables}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "bfd85d9c-2772-4660-a8f0-cdc0cd8252b3",
+      "name" : "default-database-handling",
+      "description" : "${default-database-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-database-image", "modify-database-owner", "update-database-access", "create-database", "list-databases", "create-database-access", "find-database", "modify-database-visibility", "import-database-data", "delete-database-access", "check-database-access" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "74648f9a-777e-4ef9-b97b-4c5d749d862f",
+      "name" : "update-search-index",
+      "description" : "${update-search-index}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "22492b64-c633-48a0-9678-b28669f2885b",
+      "name" : "execute-semantic-query",
+      "description" : "${execute-semantic-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "4ed919fa-edc5-44e5-9411-607786e4a86d",
+      "name" : "view-table-history",
+      "description" : "${view-table-history}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d89a2881-b642-4abb-b990-196e71372f6b",
+      "name" : "default-table-handling",
+      "description" : "${default-table-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3",
+      "name" : "view-database-view-data",
+      "description" : "${view-database-view-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f5ea431a-9b2c-4195-bcb4-9511f38e4b44",
+      "name" : "create-database-view",
+      "description" : "${create-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a5ffc20e-8b11-498c-9f3b-b5740aec24c7",
+      "name" : "default-semantics-handling",
+      "description" : "${default-semantics-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-semantic-unit", "create-semantic-concept", "execute-semantic-query", "table-semantic-analyse" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe4a01f3-6590-4df6-9ade-5a9c1fae4736",
+      "name" : "create-semantic-unit",
+      "description" : "${create-semantic-unit}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "0e12eedf-545d-4d32-ac4d-2821dcb118b8",
+      "name" : "update-table-statistic",
+      "description" : "${update-table-statistic}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e63e61a2-d852-4ad3-bfb5-92d9ceafef6a",
+      "name" : "escalated-user-handling",
+      "description" : "${escalated-user-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "find-user" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be4e1aba-e276-4241-b6ea-01dce6c52f8b",
+      "name" : "find-container",
+      "description" : "${find-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3a801b48-f3c2-4bc6-aa25-c7a91d5b32a7",
+      "name" : "default-researcher-roles",
+      "description" : "${default-researcher-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3d8104fb-8307-40f0-b4b2-c3e518957110",
+      "name" : "view-table-data",
+      "description" : "${view-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe71b907-7020-44ab-9964-da2b87264582",
+      "name" : "create-database",
+      "description" : "${create-database}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e51b63c2-48dd-4bd6-95fb-d257d21b26ba",
+      "name" : "import-database-data",
+      "description" : "${import-database-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "1f0a9b13-c2b8-474c-bc08-59dbd71835a6",
+      "name" : "modify-database-image",
+      "description" : "${modify-database-image}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a7ad038c-5c06-42fc-951c-15ac09d4df66",
+      "name" : "modify-database-owner",
+      "description" : "${modify-database-owner}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c12c1f4e-186f-4153-a795-26e79fb623d6",
+      "name" : "create-ontology",
+      "description" : "${create-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b60a5694-4099-4f7d-a7e9-4c433e0eb9c9",
+      "name" : "update-semantic-unit",
+      "description" : "${update-semantic-unit}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e9854bbb-4580-4757-b1ae-305934173249",
+      "name" : "create-database-access",
+      "description" : "${create-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "50c604c1-7c6e-43f3-9c43-2398f5eff66e",
+      "name" : "list-databases",
+      "description" : "${list-databases}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "535f1484-4514-4d24-8d97-e3f6c11a426b",
+      "name" : "create-container",
+      "description" : "${create-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f4116230-8642-4bb7-bbc8-db9c5c07b558",
+      "name" : "create-maintenance-message",
+      "description" : "${create-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "973f0999-cc70-4b28-9f43-979c470bea8e",
+      "name" : "default-data-steward-roles",
+      "description" : "${default-data-steward-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-identifier-handling", "default-semantics-handling", "escalated-semantics-handling", "default-user-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e1383fb7-d54c-4732-9146-93030eb2ca50",
+      "name" : "escalated-query-handling",
+      "description" : "${escalated-query-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "993b5c69-9eb2-42af-ac28-b4a46c6b61f2",
+      "name" : "find-user",
+      "description" : "${find-user}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e4cfdc4d-2373-477b-a8df-161db99aba00",
+      "name" : "create-foreign-identifier",
+      "description" : "${create-foreign-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6a5872a5-2b51-415d-ae2d-25a6db4a35df",
+      "name" : "escalated-semantics-handling",
+      "description" : "${escalated-semantics-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "update-semantic-unit", "create-ontology", "update-ontology", "list-ontologies", "delete-ontology", "modify-foreign-table-column-semantics", "update-semantic-concept" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "09147c48-273b-450b-8b11-7ef9b9245244",
+      "name" : "export-table-data",
+      "description" : "${export-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d14af590-60a8-4d75-b864-40ee0165bd7f",
+      "name" : "delete-database-access",
+      "description" : "${delete-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be051d45-cd74-4b13-8a45-f2d3351bd995",
+      "name" : "table-semantic-analyse",
+      "description" : "${table-semantic-analyse}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "272a79a7-e282-4261-8f7d-5d5d1364243a",
+      "name" : "update-maintenance-message",
+      "description" : "${update-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "64c16bfb-2015-48ad-a23f-637ff24419cb",
+      "name" : "default-query-handling",
+      "description" : "${default-query-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c047d521-cec3-4444-86c4-aef098489b7b",
+      "name" : "delete-maintenance-message",
+      "description" : "${delete-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "88f82262-be80-4d18-9fb4-5529da031f33",
+      "name" : "system",
+      "description" : "${system}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e14ab76b-1c24-484d-ae2d-478b8457edea",
+      "name" : "list-licenses",
+      "description" : "${list-licenses}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d4f29937-3ca0-41e9-9786-2b7b921b6cdd",
+      "name" : "modify-foreign-table-column-semantics",
+      "description" : "${modify-foreign-table-column-semantics}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "8eda9f5c-938c-4915-bed5-6a81a1de15a8",
+      "name" : "list-database-views",
+      "description" : "${list-database-views}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "b372f8f7-d203-4293-b991-ad93fb505917",
+      "name" : "escalated-database-handling",
+      "description" : "${escalated-database-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a",
+      "name" : "default-roles-dbrepo",
+      "description" : "${role_default-roles}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "3293799a-82b9-4f47-8f25-1aad2e0222fd",
+      "name" : "find-identifier",
+      "description" : "${find-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "aaa3f804-38a0-4474-b8e9-f1020c4b3f62",
+      "name" : "list-queries",
+      "description" : "${list-queries}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "76e38f7b-99bf-4d12-8d74-1c7d8812f443",
+      "name" : "update-ontology",
+      "description" : "${update-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "11f7973e-d1eb-42cb-a35d-c59dfc122775",
+      "name" : "modify-user-theme",
+      "description" : "${modify-user-theme}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f392bfcb-0be5-4fad-9ce4-8ac6396f176d",
+      "name" : "export-query-data",
+      "description" : "${export-query-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "da493b7e-fb9b-43ca-82a5-e274ad2e6b39",
+      "name" : "find-query",
+      "description" : "${find-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a4d4a788-ebcf-4d32-baed-4a85616ca037",
+      "name" : "escalated-identifier-handling",
+      "description" : "${escalated-identifier-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-foreign-identifier", "modify-identifier-metadata" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "ea38d69d-17b8-4c65-95e8-1c3501b83618",
+      "name" : "default-container-handling",
+      "description" : "${default-container-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "find-container", "list-containers" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "8b8813e0-af07-4d04-a8c1-e3f37192bace",
+      "name" : "publish-identifier",
+      "description" : "${publish-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "47f5eee7-9821-4bf8-b434-0da1f81c3e5a",
+      "name" : "default-broker-handling",
+      "description" : "${default-broker-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "71874bde-64a5-4a69-8685-d8998303a80c",
+      "name" : "delete-table-data",
+      "description" : "${delete-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7c0306fc-3b03-4c64-87d1-9a34f2073977",
+      "name" : "modify-table-column-semantics",
+      "description" : "${modify-table-column-semantics}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "cd0ee04c-4a5e-4035-a11b-f6a1165f7829",
+      "name" : "delete-container",
+      "description" : "${delete-container}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "67ee39c0-d601-4a67-a0fe-c4f0021d557e",
+      "name" : "list-containers",
+      "description" : "${list-containers}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "795c7bb8-3502-414a-a97b-2ba1cfd6a79c",
+      "name" : "persist-query",
+      "description" : "${persist-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d05e7698-ddf5-4f20-9027-771afb2cc3c7",
+      "name" : "list-identifiers",
+      "description" : "${list-identifiers}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e4bfaf36-9a5d-43e0-9fa3-0f4ea7bad8d0",
+      "name" : "default-developer-roles",
+      "description" : "${default-developer-roles}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "escalated-query-handling", "escalated-broker-handling", "default-table-handling", "escalated-database-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-maintenance-handling", "escalated-container-handling", "escalated-table-handling", "default-identifier-handling" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "e2cb054e-ea41-4ab0-881b-e6f576f7424e",
+      "name" : "create-semantic-concept",
+      "description" : "${create-semantic-concept}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "feb612cc-96a6-4ed2-aaa5-01f39b25beb5",
+      "name" : "insert-table-data",
+      "description" : "${insert-table-data}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a0942e33-441b-4343-9f02-4353d03f7bbb",
+      "name" : "find-database",
+      "description" : "${find-database}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6a0bb740-4448-49be-aee8-6dd183325be5",
+      "name" : "delete-foreign-table",
+      "description" : "${delete-foreign-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "7f3652c7-3073-4566-ab63-25385495ebc3",
+      "name" : "modify-database-visibility",
+      "description" : "${modify-database-visibility}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "4a5df51d-f14d-41a2-ad70-6521df5a5b4f",
+      "name" : "offline_access",
+      "description" : "${role_offline-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fd41c4c3-d2f8-4f49-84c7-dba84e9a5575",
+      "name" : "execute-query",
+      "description" : "${execute-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "2963c2bb-b129-4224-b98f-c8eeab8e72d1",
+      "name" : "create-table",
+      "description" : "${create-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "0c487c93-448f-4a82-8b9f-ebd8a0904bf8",
+      "name" : "find-foreign-user",
+      "description" : "${find-foreign-user}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "cf9735a9-fb70-4cc5-b5f4-75afc4e5654b",
+      "name" : "modify-identifier-metadata",
+      "description" : "${modify-identifier-metadata}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "64c2b8f2-1527-4928-81ea-b2651512d028",
+      "name" : "delete-ontology",
+      "description" : "${delete-ontology}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d6e38368-b40f-423b-82e4-e8aa595237c9",
+      "name" : "find-maintenance-message",
+      "description" : "${find-maintenance-message}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fd1cc463-3e67-49d9-81b8-2cd90c1daa9c",
+      "name" : "check-database-access",
+      "description" : "${check-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "74013867-e426-46cc-ab98-2f4a9225ad1e",
+      "name" : "find-table",
+      "description" : "${find-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a2cc60df-d280-46c5-a539-92e2aa249b4a",
+      "name" : "modify-user-information",
+      "description" : "${modify-user-information}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "c367241f-b5b5-491f-84d5-07fe1bef3877",
+      "name" : "default-identifier-handling",
+      "description" : "${default-identifier-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-identifier", "list-identifiers", "create-identifier", "find-identifier", "publish-identifier" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "ba1ad8f2-39aa-487d-987f-645e8a459559",
+      "name" : "delete-table",
+      "description" : "${delete-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "09f7bdb0-296f-46c8-a3a3-8f9254fb17e4",
+      "name" : "list-maintenance-messages",
+      "description" : "${list-maintenance-messages}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "fe3bc45c-61c2-4ece-bcaf-d410dc7de501",
+      "name" : "update-database-access",
+      "description" : "${update-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "f43e86ed-76de-4ca8-9b5e-c292c9359bfe",
+      "name" : "escalated-broker-handling",
+      "description" : "${escalated-broker-handling}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "916b1e65-f60c-42cd-96e4-5c98ffc1ba3c",
+      "name" : "uma_authorization",
+      "description" : "${role_uma_authorization}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "d1afa3ed-bf4f-469a-a061-ad7325fb8d9e",
+      "name" : "delete-database-view",
+      "description" : "${delete-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "6f044bad-6651-4408-bffa-20c2d8f92eee",
+      "name" : "create-identifier",
+      "description" : "${create-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "be91195a-e30a-4d15-a8da-0aca0a68782f",
+      "name" : "escalated-table-handling",
+      "description" : "${escalated-table-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-foreign-table" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "98bee7d6-d78c-4e7f-b6a3-3705968b248c",
+      "name" : "list-ontologies",
+      "description" : "${list-ontologies}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "15720c6b-027d-4d53-a0ff-0124bfab7c4c",
+      "name" : "re-execute-query",
+      "description" : "${re-execute-query}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "a9b5181a-8135-41d3-9862-ef80af42211d",
+      "name" : "delete-identifier",
+      "description" : "${delete-identifier}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    }, {
+      "id" : "469c2e63-cda6-48d4-ab8f-eb59a2c69798",
+      "name" : "find-database-view",
+      "description" : "${find-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
+    } ],
+    "client" : {
+      "realm-management" : [ {
+        "id" : "4628f654-f8f3-483b-8f92-2a7fc5930b14",
+        "name" : "query-realms",
+        "description" : "${role_query-realms}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "95c2cc47-12f5-4d73-8b74-67e270c45ade",
+        "name" : "manage-authorization",
+        "description" : "${role_manage-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "824791f3-c345-42f8-b103-b7e6d7e40114",
+        "name" : "manage-identity-providers",
+        "description" : "${role_manage-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "1f840202-b7e2-4195-bac9-64e64dad2037",
+        "name" : "view-identity-providers",
+        "description" : "${role_view-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "3c32c096-bb13-44c9-a080-d756a48a9ea3",
+        "name" : "query-clients",
+        "description" : "${role_query-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "e4b85a68-7f31-4fcf-89a2-f10d7df358e9",
+        "name" : "view-authorization",
+        "description" : "${role_view-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7d317752-ae56-46f2-a2ce-67c64d1b35f6",
+        "name" : "view-users",
+        "description" : "${role_view-users}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-users", "query-groups" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "28824208-976e-4622-b4d7-3d18efbb46fa",
+        "name" : "realm-admin",
+        "description" : "${role_realm-admin}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-realms", "view-identity-providers", "manage-identity-providers", "manage-authorization", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "query-groups", "create-client", "manage-clients", "manage-events", "impersonation", "view-events", "manage-realm" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "57e846a2-930d-4621-819d-c35086507146",
+        "name" : "manage-users",
+        "description" : "${role_manage-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7fad9cde-bf96-475a-9174-14a87da51f95",
+        "name" : "view-realm",
+        "description" : "${role_view-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "bbcac294-d78a-4ea1-a4bf-0384266d2fe1",
+        "name" : "query-users",
+        "description" : "${role_query-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "480e1437-ab9e-47de-b47a-edc6b6e285de",
+        "name" : "view-clients",
+        "description" : "${role_view-clients}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "realm-management" : [ "query-clients" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "b9a9a8f5-f91e-4e73-9e88-1cdf42bd49f9",
+        "name" : "create-client",
+        "description" : "${role_create-client}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "4d1397fb-247c-436f-b26f-124cd89afb08",
+        "name" : "query-groups",
+        "description" : "${role_query-groups}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "e31f522b-b283-4ae1-b875-52afcd98b1d2",
+        "name" : "impersonation",
+        "description" : "${role_impersonation}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "51822d02-fa28-4a49-89da-bc534719d8a8",
+        "name" : "manage-clients",
+        "description" : "${role_manage-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "b2743ce5-0ce8-4157-ae00-f693560f0b39",
+        "name" : "manage-events",
+        "description" : "${role_manage-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "7ea3d7e0-9bf4-438a-b773-243daf622aaa",
+        "name" : "view-events",
+        "description" : "${role_view-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      }, {
+        "id" : "fb73f6f5-0ed5-41d0-852c-0eb3b195b15a",
+        "name" : "manage-realm",
+        "description" : "${role_manage-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+        "attributes" : { }
+      } ],
+      "security-admin-console" : [ ],
+      "dbrepo-client" : [ ],
+      "admin-cli" : [ ],
+      "rabbitmq-client" : [ ],
+      "account-console" : [ ],
+      "broker" : [ {
+        "id" : "de0cfd5e-c2fe-4082-ac39-e3b092139a0f",
+        "name" : "read-token",
+        "description" : "${role_read-token}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "88694c91-753d-4c44-9740-ec9ac06bba45",
+        "attributes" : { }
+      } ],
+      "account" : [ {
+        "id" : "acd78c04-eefc-4344-a5b4-3fc83d848936",
+        "name" : "delete-account",
+        "description" : "${role_delete-account}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "939be844-8c49-45b3-9ca1-4b10a454b346",
+        "name" : "view-profile",
+        "description" : "${role_view-profile}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "e52fdf00-3e73-4c17-bc1c-643493710a6b",
+        "name" : "view-applications",
+        "description" : "${role_view-applications}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "b02a822e-a708-420a-bddc-1a315033fd7c",
+        "name" : "view-consent",
+        "description" : "${role_view-consent}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "c590e5f5-2cbf-4151-b1dc-96c454f1f654",
+        "name" : "view-groups",
+        "description" : "${role_view-groups}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "15974151-6c13-426b-8cc3-7683dd1311e1",
+        "name" : "manage-account-links",
+        "description" : "${role_manage-account-links}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "c12d8d94-c2df-498e-bbe4-2f934a83ae92",
+        "name" : "manage-consent",
+        "description" : "${role_manage-consent}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "view-consent" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      }, {
+        "id" : "55f85811-bded-4d6b-8f7b-45844b963875",
+        "name" : "manage-account",
+        "description" : "${role_manage-account}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "manage-account-links" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+        "attributes" : { }
+      } ]
+    }
+  },
+  "groups" : [ {
+    "id" : "f2ce17fe-7b15-47a4-bbf8-86f415298fa9",
+    "name" : "data-stewards",
+    "path" : "/data-stewards",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-data-steward-roles" ],
+    "clientRoles" : { }
+  }, {
+    "id" : "124d9888-0b6e-46aa-8225-077dcedaf16e",
+    "name" : "developers",
+    "path" : "/developers",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-developer-roles" ],
+    "clientRoles" : { }
+  }, {
+    "id" : "f467c38e-9041-4faa-ae0b-39cec65ff4db",
+    "name" : "researchers",
+    "path" : "/researchers",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-researcher-roles" ],
+    "clientRoles" : { }
+  }, {
+    "id" : "2b9f94b4-d434-4a98-8eab-25678cfee983",
+    "name" : "system",
+    "path" : "/system",
+    "subGroups" : [ ],
+    "attributes" : { },
+    "realmRoles" : [ "default-system-roles" ],
+    "clientRoles" : { }
+  } ],
+  "defaultRole" : {
+    "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a",
+    "name" : "default-roles-dbrepo",
+    "description" : "${role_default-roles}",
+    "composite" : false,
+    "clientRole" : false,
+    "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0"
+  },
+  "defaultGroups" : [ "/researchers" ],
+  "requiredCredentials" : [ "password" ],
+  "otpPolicyType" : "totp",
+  "otpPolicyAlgorithm" : "HmacSHA1",
+  "otpPolicyInitialCounter" : 0,
+  "otpPolicyDigits" : 6,
+  "otpPolicyLookAheadWindow" : 1,
+  "otpPolicyPeriod" : 30,
+  "otpPolicyCodeReusable" : false,
+  "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ],
+  "localizationTexts" : { },
+  "webAuthnPolicyRpEntityName" : "keycloak",
+  "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyRpId" : "",
+  "webAuthnPolicyAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyRequireResidentKey" : "not specified",
+  "webAuthnPolicyUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyCreateTimeout" : 0,
+  "webAuthnPolicyAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyAcceptableAaguids" : [ ],
+  "webAuthnPolicyExtraOrigins" : [ ],
+  "webAuthnPolicyPasswordlessRpEntityName" : "keycloak",
+  "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyPasswordlessRpId" : "",
+  "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified",
+  "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyPasswordlessCreateTimeout" : 0,
+  "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ],
+  "webAuthnPolicyPasswordlessExtraOrigins" : [ ],
+  "scopeMappings" : [ {
+    "clientScope" : "rabbitmq.tag:administrator",
+    "roles" : [ "escalated-broker-handling" ]
+  }, {
+    "clientScope" : "rabbitmq.tag:management",
+    "roles" : [ "default-broker-handling" ]
+  } ],
+  "clientScopeMappings" : {
+    "account" : [ {
+      "client" : "account-console",
+      "roles" : [ "manage-account", "view-groups" ]
+    } ]
+  },
+  "clients" : [ {
+    "id" : "e767a4a6-79e9-4e08-82b7-1076e1a09142",
+    "clientId" : "account",
+    "name" : "${client_account}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/dbrepo/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/realms/dbrepo/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "d3c4a04e-39ce-4549-a34a-11e25774cd96",
+    "clientId" : "account-console",
+    "name" : "${client_account-console}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/dbrepo/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/realms/dbrepo/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+",
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "22d90d9c-9881-474c-8dfd-a62c808a9f1c",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "81ef0f59-a5ca-4be4-a1d1-0c32edf1cfd6",
+    "clientId" : "admin-cli",
+    "name" : "${client_admin-cli}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : false,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "88694c91-753d-4c44-9740-ec9ac06bba45",
+    "clientId" : "broker",
+    "name" : "${client_broker}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : true,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "6b7ef364-4132-4831-b4e2-b6e9e9dc63ee",
+    "clientId" : "dbrepo-client",
+    "name" : "${dbrepo-client}",
+    "description" : "",
+    "rootUrl" : "",
+    "adminUrl" : "",
+    "baseUrl" : "",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : true,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG",
+    "redirectUris" : [ "*" ],
+    "webOrigins" : [ "*" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : true,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "oidc.ciba.grant.enabled" : "false",
+      "client.secret.creation.time" : "1680085365",
+      "backchannel.logout.session.required" : "true",
+      "post.logout.redirect.uris" : "*",
+      "oauth2.device.authorization.grant.enabled" : "false",
+      "backchannel.logout.revoke.offline.tokens" : "false"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : true,
+    "nodeReRegistrationTimeout" : -1,
+    "protocolMappers" : [ {
+      "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
+      "name" : "preferred_username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "preferred_username",
+        "userinfo.token.claim" : "true"
+      }
+    }, {
+      "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
+      "name" : "aud",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "claim.value" : "dbrepo",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "access.tokenResponse.claim" : "false"
+      }
+    }, {
+      "id" : "0b4c644f-0cf0-4794-8395-d5d83009dabe",
+      "name" : "uid",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "CUSTOM_ID",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "uid",
+        "jsonType.label" : "String"
+      }
+    } ],
+    "defaultClientScopes" : [ "roles", "attributes" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+  }, {
+    "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
+    "clientId" : "rabbitmq-client",
+    "name" : "${rabbitmq-client}",
+    "description" : "",
+    "rootUrl" : "",
+    "adminUrl" : "",
+    "baseUrl" : "",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "JEC2FexxrX4N65fLeDGukAl6R3Lc9y0u",
+    "redirectUris" : [ "*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : true,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "oidc.ciba.grant.enabled" : "false",
+      "client.secret.creation.time" : "1680000860",
+      "backchannel.logout.session.required" : "true",
+      "post.logout.redirect.uris" : "*",
+      "oauth2.device.authorization.grant.enabled" : "false",
+      "backchannel.logout.revoke.offline.tokens" : "false"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : -1,
+    "protocolMappers" : [ {
+      "id" : "01a937ed-f0e8-4137-80f3-3be3c447f7fb",
+      "name" : "username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "false",
+        "user.attribute" : "username",
+        "id.token.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
+      "name" : "Audience",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "claim.value" : "rabbitmq",
+        "userinfo.token.claim" : "false",
+        "id.token.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "access.tokenResponse.claim" : "false"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "roles", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+  }, {
+    "id" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
+    "clientId" : "realm-management",
+    "name" : "${client_realm-management}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : true,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "f205c451-9524-4380-acc3-947f7ecb6b7c",
+    "clientId" : "security-admin-console",
+    "name" : "${client_security-admin-console}",
+    "rootUrl" : "${authAdminUrl}",
+    "baseUrl" : "/admin/dbrepo/console/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "redirectUris" : [ "/admin/dbrepo/console/*" ],
+    "webOrigins" : [ "+" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "post.logout.redirect.uris" : "+",
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "c4d54410-3f22-4259-9571-94da2c43b752",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  } ],
+  "clientScopes" : [ {
+    "id" : "69f4ecf0-4165-49ab-bf0d-38409b15b706",
+    "name" : "rabbitmq.tag:administrator",
+    "description" : "administrator",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "7f6e9b44-e2eb-417d-b0fe-db820c9a6564",
+    "name" : "email",
+    "description" : "OpenID Connect built-in scope: email",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${emailScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
+      "name" : "email verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "emailVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email_verified",
+        "jsonType.label" : "boolean"
+      }
+    }, {
+      "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
+      "name" : "email",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "email",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "b9da268f-6745-49dc-a764-3c54e385accc",
+    "name" : "profile",
+    "description" : "OpenID Connect built-in scope: profile",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${profileScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
+      "name" : "username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "preferred_username",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
+      "name" : "gender",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "gender",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "gender",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
+      "name" : "birthdate",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "birthdate",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "birthdate",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
+      "name" : "full name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-full-name-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "userinfo.token.claim" : "true"
+      }
+    }, {
+      "id" : "f757d8ec-e181-429c-9287-9ad0600b061f",
+      "name" : "profile",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "profile",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "profile",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
+      "name" : "updated at",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "updatedAt",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "updated_at",
+        "jsonType.label" : "long"
+      }
+    }, {
+      "id" : "841ea785-26ab-429a-a420-09ce3948924d",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
+      "name" : "website",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "website",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "website",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "475f071d-5149-4379-b928-76482f5f519c",
+      "name" : "zoneinfo",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "zoneinfo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "zoneinfo",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
+      "name" : "middle name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "middleName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "middle_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
+      "name" : "picture",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "picture",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "picture",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
+      "name" : "nickname",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "nickname",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "nickname",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "627fa054-08eb-4206-af71-9e838e984b8b",
+    "name" : "microprofile-jwt",
+    "description" : "Microprofile - JWT built-in scope",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "e6cc53e5-5d7e-468e-88c8-0737dd3dc759",
+      "name" : "groups",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "multivalued" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "groups",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "83b4444c-10fc-44e8-a0c0-0c1da1f9bba3",
+      "name" : "upn",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "upn",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "4122ff9e-ad3c-4142-afc6-9aefdecfc86d",
+    "name" : "role_list",
+    "description" : "SAML role list",
+    "protocol" : "saml",
+    "attributes" : {
+      "consent.screen.text" : "${samlRoleListScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    },
+    "protocolMappers" : [ {
+      "id" : "bb0747fa-c008-4af3-93be-e7739650ebd5",
+      "name" : "role list",
+      "protocol" : "saml",
+      "protocolMapper" : "saml-role-list-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "single" : "false",
+        "attribute.nameformat" : "Basic",
+        "attribute.name" : "Role"
+      }
+    } ]
+  }, {
+    "id" : "2e76447d-fbe7-4fa7-a16c-54a381b960ae",
+    "name" : "rabbitmq.configure:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "52aad832-c6c4-49df-8a04-6ad4a406fdfa",
+    "name" : "phone",
+    "description" : "OpenID Connect built-in scope: phone",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${phoneScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
+      "name" : "phone number",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumber",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
+      "name" : "phone number verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumberVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number_verified",
+        "jsonType.label" : "boolean"
+      }
+    } ]
+  }, {
+    "id" : "f64d64e8-57ce-4eb2-b99e-9f02fdbd99f9",
+    "name" : "web-origins",
+    "description" : "OpenID Connect scope for add allowed web origins to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false",
+      "consent.screen.text" : ""
+    },
+    "protocolMappers" : [ {
+      "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
+      "name" : "allowed web origins",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-allowed-origins-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ]
+  }, {
+    "id" : "55341d34-0086-4173-ae61-d9b175b179d8",
+    "name" : "acr",
+    "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "58ea3217-0fff-4207-9d08-919f5493b629",
+      "name" : "acr loa level",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-acr-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "userinfo.token.claim" : "true"
+      }
+    } ]
+  }, {
+    "id" : "a02c2c38-923c-46ec-9899-321412b388e5",
+    "name" : "attributes",
+    "description" : "User Attributes",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    },
+    "protocolMappers" : [ {
+      "id" : "78c461c1-f3f9-4d10-8835-097f13bdcd60",
+      "name" : "Theme",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "aggregate.attrs" : "false",
+        "multivalued" : "false",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "theme_dark",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "attributes.theme_dark"
+      }
+    } ]
+  }, {
+    "id" : "06062e22-89c0-4e1d-a25b-2483903b02d5",
+    "name" : "rabbitmq.write:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "db63e03b-7918-492f-997b-f2dda98f3b39",
+    "name" : "rabbitmq.tag:management",
+    "description" : "management",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
+    "name" : "offline_access",
+    "description" : "OpenID Connect built-in scope: offline_access",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "consent.screen.text" : "${offlineAccessScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    }
+  }, {
+    "id" : "425abf4a-2ee2-431d-aa92-e373a36fe556",
+    "name" : "address",
+    "description" : "OpenID Connect built-in scope: address",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${addressScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
+      "name" : "address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-address-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute.formatted" : "formatted",
+        "user.attribute.country" : "country",
+        "user.attribute.postal_code" : "postal_code",
+        "userinfo.token.claim" : "true",
+        "user.attribute.street" : "street",
+        "id.token.claim" : "true",
+        "user.attribute.region" : "region",
+        "access.token.claim" : "true",
+        "user.attribute.locality" : "locality"
+      }
+    } ]
+  }, {
+    "id" : "c96f0b73-ea79-4b46-93ef-d1092297f855",
+    "name" : "rabbitmq.read:*/*",
+    "description" : "",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false",
+      "gui.order" : "",
+      "consent.screen.text" : ""
+    }
+  }, {
+    "id" : "37f61543-dad7-4a82-8e10-77acdd1eefdc",
+    "name" : "roles",
+    "description" : "OpenID Connect scope for add user roles to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${rolesScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    }, {
+      "id" : "2defedf5-9af3-4531-822c-a879dedcd29d",
+      "name" : "realm roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "realm_access.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    }, {
+      "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
+      "name" : "client roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-client-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "resource_access.${client_id}.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    } ]
+  } ],
+  "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management" ],
+  "defaultOptionalClientScopes" : [ "rabbitmq.write:*/*", "offline_access", "rabbitmq.configure:*/*", "roles", "role_list", "address", "phone", "acr", "microprofile-jwt", "email", "attributes", "profile", "rabbitmq.read:*/*", "web-origins" ],
+  "browserSecurityHeaders" : {
+    "contentSecurityPolicyReportOnly" : "",
+    "xContentTypeOptions" : "nosniff",
+    "referrerPolicy" : "no-referrer",
+    "xRobotsTag" : "none",
+    "xFrameOptions" : "SAMEORIGIN",
+    "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+    "xXSSProtection" : "1; mode=block",
+    "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
+  },
+  "smtpServer" : { },
+  "eventsEnabled" : false,
+  "eventsListeners" : [ "jboss-logging" ],
+  "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
+  "adminEventsEnabled" : false,
+  "adminEventsDetailsEnabled" : false,
+  "identityProviders" : [ ],
+  "identityProviderMappers" : [ ],
+  "components" : {
+    "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ {
+      "id" : "4d3f9f14-f5d2-4b0c-8ea7-e6d078aa2191",
+      "name" : "Max Clients Limit",
+      "providerId" : "max-clients",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "max-clients" : [ "200" ]
+      }
+    }, {
+      "id" : "f35bce67-1e75-408b-b065-52183368d4fd",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "0efa669d-1017-4b4a-82e1-c2eaf72de2c9",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "528fb423-d66e-472e-9120-1f03ba9e0f18",
+      "name" : "Consent Required",
+      "providerId" : "consent-required",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "3ab11d74-5e76-408a-b85a-26bf8950f979",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ]
+      }
+    }, {
+      "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
+      "name" : "Trusted Hosts",
+      "providerId" : "trusted-hosts",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "host-sending-registration-request-must-match" : [ "true" ],
+        "client-uris-must-match" : [ "true" ]
+      }
+    }, {
+      "id" : "f565cb47-3bcf-4078-8f94-eb4179c375b8",
+      "name" : "Full Scope Disabled",
+      "providerId" : "scope",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "104ec5a9-025b-4c44-8ac0-82d22887ca3e",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ]
+      }
+    } ],
+    "org.keycloak.userprofile.UserProfileProvider" : [ {
+      "id" : "fb763636-e1ea-49c7-adca-ea105cdec4ad",
+      "providerId" : "declarative-user-profile",
+      "subComponents" : { },
+      "config" : {
+        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
+      }
+    } ],
+    "org.keycloak.keys.KeyProvider" : [ {
+      "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51",
+      "name" : "rsa-enc-generated",
+      "providerId" : "rsa-enc-generated",
+      "subComponents" : { },
+      "config" : {
+        "privateKey" : [ "MIIEowIBAAKCAQEA3b1tNLfcjFLUw9UShVDNf+ZD8sQqb4YBaIXcSJTX/zDQUPiCp176BBGI3s4VplDArnOW+LumozmKogeoHEnGEIDW8ovgK5uMU9tSA2p0qqGBUMOdR8YATTIfCJe7qGiiuGa3WZy3sQLM70SuRzx02YU8gvUcvl2Js4KyqAziOUX/w3Wa59H9jjGNUXYyqaPWJp73eHzbVYWySzyLG22mVlcUtBx5siL5T2/Xu0p9z4l7/bapwwmOVi1ZrcHjbEAwdGEiSMGI/uWqAF+r1BRpmJLR7HNXcL3eK4/56VYLaiwSejfyYeRFMITEn/UxGYhcXZ5xMUUCG0TxjBhLYpTBuwIDAQABAoIBAA4dwebcxkrH99Poa8+WkiE7JgaS9sahx9OBI2xwJANoIU2TpzGuNLQZ76uLgB+rPWZTD9Xm5a1iJjwOyQ9/937TzPCk91D0tpgcusRikb8jx/6TGB9acL4kBjYUVCCHr3BA2G75MKKGtJ2OMvAbCQSosZj+r2VDwYFEPUkV2jheE5JHSBkwyIRrus3JCwu8gu5fyCg9z8ljcxJxI5HIsi4v8Z21aCw/cLj7h5cMt44wCjQz4rOfYNBEFeHDtlfR1QtWKgjm4ZHHJbKrzf9b2kQXclziceEbSM0tYbROEXKi+s0Zc+z3HEG89vv0vfN400clmzzIAijKY6gg3pPRWdECgYEA+lnWYbSlXDMNYx6RBXm1RnlMUYIm4oy4/9ljgnoGJ6WCn3SjFkgaDtiKfGIG1BSB85r04pAPANgcWHf5tWDnq0ARvBVG0BX2bKd++7B3D4d3CRYKCwm88SslJXv9dfHVhq4+zViFPiUWwT20A72jCuUCvL88y5fh/YBecfdh+jECgYEA4r5RD0NB9dMaeg5/jk/GEHIo4Z9KLc6FrSoOFo2xFkPOy1sgDpDOiNtypuWvniO7k7Ose3DS3hlfTMsKzIW/CgQJ20+Y4cvBWDaOsRxfjj7w3d+jH5OSJdKKSzTrgLKc9ZhlRzVXy0J0hipIA6HG5kdVdLXmh85ITmf1CbJhE6sCgYBjPVeBNbXTHZ2x6/z62aslO5IoQVqetb/kE82hfDOSZcao5Ph9Lam+ttH2ynkAevykj4mBgi+gWwqpey2uW7KaLPSaxShj9kDQA3mP1fzsV/u0y1rB02Nlin/YIxVvOqU1FT9p8SwoXVVu1sHUNck62VtDbN9xqUx5S/ikXrclEQKBgQCoTssOwEcK+Vty9KYcdfy4onTUHZBLdjxl8Iyqkxy7QTQUYRznkvesQPDXEDGO+kk3dyx2KKZt9Hl4IFNww2quPZcvcuMx4DQxjbXXpA8OIIxcta95NepLJwA+mRai3nKCH1A2TlNP7pFeMa5o+8IPly3Ix2lKr4Wepa4PN5i1pwKBgCZ1QP6XAOERl9NznNmU0rXVcvYNP4PIIfQWfvGsldZ4QKkmjjAGiS0/oYqdWs+UDRZyCRChaVjDXO9fk0PEG5OGKAj9nyiYCT/M8xtJ3UeP5ffZZvJ/vnye3QdDIo1e38ZzsWwJHmLYw7fRqY9W5Vxo0Vsy22U3CJY70KTxVdTy" ],
+        "keyUse" : [ "ENC" ],
+        "certificate" : [ "MIICmzCCAYMCBgGG3GWycDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdvW00t9yMUtTD1RKFUM1/5kPyxCpvhgFohdxIlNf/MNBQ+IKnXvoEEYjezhWmUMCuc5b4u6ajOYqiB6gcScYQgNbyi+Arm4xT21IDanSqoYFQw51HxgBNMh8Il7uoaKK4ZrdZnLexAszvRK5HPHTZhTyC9Ry+XYmzgrKoDOI5Rf/DdZrn0f2OMY1RdjKpo9Ymnvd4fNtVhbJLPIsbbaZWVxS0HHmyIvlPb9e7Sn3PiXv9tqnDCY5WLVmtweNsQDB0YSJIwYj+5aoAX6vUFGmYktHsc1dwvd4rj/npVgtqLBJ6N/Jh5EUwhMSf9TEZiFxdnnExRQIbRPGMGEtilMG7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAK3kQ1VkQrzvSWvmXmazmNoA1ZiPzRDs1XhGUWxgsxzgPylr3dGBuqQbKvgnLUBQLSqlJHpI4fZflHswu1qrvVZYtekPcGef4WhcKAu2i1RwxrKa6RJQ1tRbrLuVYCzPv5p/DWgltWVn88aoLnqQn0SK/0PB/o4a4Cm7Kq2ZzCr1dACBr06LvOHsc7249OySmbG4HH+pLK6jVURhZ9VaObqAHe2FJBVVoIzURbdiRRURqumrIvbnpeaU1aFyg6ED5wTnXvmMPmVPt9F79mcB33bASO5wyu00X8t1hyN2Show2l2vxLACGUzVkTQt15s7uDLKE7qLmKSR3EuSGXWv3wA=" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "RSA-OAEP" ]
+      }
+    }, {
+      "id" : "230cb681-9ceb-4b1b-8a4c-929a11b08de0",
+      "name" : "hmac-generated-hs512",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "8a489935-9a95-459b-9059-59b438ef0fa8" ],
+        "secret" : [ "xSCVgBlrLPWoF54gKQdR7BqXlfNaCD43xtS_ZgQRC0tGNAbqhy2Q9y8LdD2IR7K__8VGaDGYtyZayopgTebhDBb4gHDjDOBX7flhFYRrm0G3aTIuCIyFG-bPULwmyP_oHeC6tjwdQhqx5G0tE2mQQqPC9dDZuUA5I7QREIGK8cI" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "HS512" ]
+      }
+    }, {
+      "id" : "28ca0b6d-b2e2-4785-b04b-2391e6344e30",
+      "name" : "aes-generated",
+      "providerId" : "aes-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "6dc4834f-a1de-4cfe-a29d-e84ac8e9b1a8" ],
+        "secret" : [ "HpuzG_jWYKwypLeoPEMC4A" ],
+        "priority" : [ "100" ]
+      }
+    }, {
+      "id" : "bd7945cf-6d35-4e03-9c3a-197f2dc76973",
+      "name" : "hmac-generated",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "5034d264-cb50-4006-a59e-2ce636eb5f38" ],
+        "secret" : [ "ToVIw-a4IE-Yp9JpP8ztb8NAICYO8CT3tUiDPT6DdiBcgzKJ9Ym9vspxGVdmPceX3mAgbnGLAcTx1PkInSVrbZs-tX9QXFwdlyGbewhKiNpH8wEg32Wk4GuUDpTv8JCsymgWyQBY681jvIMv05eCoK2QWpqCzcgP828KM5peCzo" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "HS256" ]
+      }
+    }, {
+      "id" : "2293ff99-3c6d-46d1-8635-5e679d5b134a",
+      "name" : "rsa-generated",
+      "providerId" : "rsa-generated",
+      "subComponents" : { },
+      "config" : {
+        "privateKey" : [ "MIIEpAIBAAKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQABAoIBADNcMt6hAHub4JTAYS6Mra0EPRBO2XhWmACBrv3+8ETClXd5475KPLDewgRVtlmtbwU8G8awUXESQgPS9lfiqvQhPreA3cHlm6oP2WMKOEtakr2s8I+frsTBLCo0Ini9RaSzjoVVgS0zofyhASKi+T970MafSj5P3XNb8YBFdXgoYDiA7FXLH6a/+m7LScL+wGcFMAAeYESxZbMQLfH3v8L+4EcTraiwjLG17ZdlF3dpybMyUSse6ZQ/PdlyvBuzzLXhN6Ce2gd9ATfS+YWTzo7Yf+GU+ex5bIpVOfHqtuM/hyq7YGKENClsXwNZIAoFnvGCbvECAfgyapVrD30IfykCgYEA0rgsSZ82pxT40NxwgBD1g9lbNVBKXphRB/3S078qusUzJjT7AldEj4imGPhAbI7bI8gAeWJsp1XJWkjM8ktaVrh+NQl7p8e9OPh0pQF/5Bdg8ajbjXESpjnaU66pVYRQy/d+jNli/YRAHX5RUfsBl+6W4+WSVMGmKBiqJsur+ecCgYEAz1YVXClcmUnyZem5B+2E9noIzjF6ROE+jIb6rawM85P3Xd0lXtECQavtxw+Qk7I32qOwrxl1UpK2foVel3pazi+4OpMfmqtYGenRP1Zk1cZwrDo0cIemTDGjj3kJ8tYn12CGolFQpJZgK6OHzvG0tOxI5VZgjIViWNPe1PGWXtUCgYEAxXGNDe8BZs1f11S2lUlOw5yGug3hoYFXbAWJ5p7Ziuf8ZXB/QlJDC7se54a11wKEk6Jzz0lKRgE8CjzszJuOqnN0zn10QGIIC7nCklo1W6QMUmPGVWH994N976tZP6gbjQL6sT+AYcvpx7j0ubxYYeRNvnz+ACzzY964kGGHY0ECgYEAumlwPPNnMN7+VEjGNm2D7UMdJZ3wi3tkjF5ThdA5uMohTsAk+FG80KSu3RmOaGyEsUwY7+VYyYvlDm4E9PZqLBVVczyR3rMNPAcwPd0EPfvzk7WlLkOX7ct3fehaXH3VRlyfz9KCSeh1wOZ/lT1VtpD2nVOC7PSDzs92+kfXZZ0CgYAnrD1y4skgXkdwolZ3unn3EFyGm2d+X5aMTHwQPdWxqoNIAl/9wdghlzihwnPhhsxq1WzlxuC3V2IMrNPtRx70Mi+FbSmR5m4Xx5RptgMtMlwno+L40PzNJgMjHGjt0wcx3Vel8wuohDtnqMyS7P5nG1/TQx0Cyzwn7QOXlNpgbQ==" ],
+        "keyUse" : [ "SIG" ],
+        "certificate" : [ "MIICmzCCAYMCBgGG3GWyBTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqqcdDYFZZb28M0tEJzEP77FmD/Xqioyj9zWX6VwUSOMAgmMmn8eqs9hT9T0a+q4YTo9tUW1PNbUpwprA5b4Uk04DcIajxDVMUR/PjcHytmkqwVskq9AZW/Vngdoo+8tSbuIybwe/3Vwt266hbHpDcM97a+DXcYooRl7tQWCEX7RP27wQrMD9epDQ6IgKayZg9vC9/03dsIqwH9jXQRiZlFvwiEKhX2aY7lPGBaCK414JO00K/Z49iov9TRa/IYVbSt5qwgrx6DcqsBSPwOnI6A85UGfeUEZ/7coVJiL7RvBlsllapsL9eWTbQajVh94k9Ei3sibEPbtH+U2OAM78zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASnN1Cuif1sdfEK2kWAURSXGJCohCROLWdKFjaeHPRaEfpbFJsgxW0Yj3nwX5O3bUlOWoTyENwnXSsXMQsqnNi+At32CKaKO8+AkhAbgQL9F0B+KeJwmYv3cUj5N/LYkJjBvZBzUZ4Ugu5dcxH0k7AktLAIwimkyEnxTNolOA3UyrGGpREr8MCKWVr10RFuOpF/0CsJNNwbHXzalO9D756EUcRWZ9VSg6QVNso0YYRKTnILWDn9hcTRnqGy3SHo3anFTqQZ+BB57YbgFWy6udC0LYRB3zdp6zNti87eu/VEymiDY/mmo1AB8Tm0b6vxFz4AKcL3ax5qS6YnZ9efSzk=" ],
+        "priority" : [ "100" ]
+      }
+    } ]
+  },
+  "internationalizationEnabled" : false,
+  "supportedLocales" : [ ],
+  "authenticationFlows" : [ {
+    "id" : "88e5d526-2298-413c-a904-133ad839d47f",
+    "alias" : "Account verification options",
+    "description" : "Method with which to verity the existing account",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-email-verification",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Verify Existing Account by Re-authentication",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "a690c715-fbae-4c20-b680-bd4010718761",
+    "alias" : "Browser - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "ad6d407e-c73e-4439-baf3-d7c99c6cb6ad",
+    "alias" : "Direct Grant - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "direct-grant-validate-otp",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "e5d03405-e10a-408a-adb2-41dbb4f24515",
+    "alias" : "First broker login - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "96b93843-62d0-44f1-84dd-21cc5f95f523",
+    "alias" : "Handle Existing Account",
+    "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-confirm-link",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Account verification options",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "088f4051-36ab-4952-a4f2-4ba53c408083",
+    "alias" : "Reset - Conditional OTP",
+    "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-otp",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "05f37bb2-779d-4e3f-ad1b-f6eb33bb3de4",
+    "alias" : "User creation or linking",
+    "description" : "Flow for the existing/non-existing user alternatives",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticatorConfig" : "create unique user config",
+      "authenticator" : "idp-create-user-if-unique",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Handle Existing Account",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "300a5647-7d2c-4348-9f1f-51504bfda1c4",
+    "alias" : "Verify Existing Account by Re-authentication",
+    "description" : "Reauthentication of existing account",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-username-password-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "First broker login - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "26afc672-314b-4ad9-9711-7aaeafd7c00c",
+    "alias" : "browser",
+    "description" : "browser based authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "auth-cookie",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "auth-spnego",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "identity-provider-redirector",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 25,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 30,
+      "autheticatorFlow" : true,
+      "flowAlias" : "forms",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "9b301f6c-eda7-4da0-ba09-1a6454ff910d",
+    "alias" : "clients",
+    "description" : "Base authentication for clients",
+    "providerId" : "client-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "client-secret",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-jwt",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-secret-jwt",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 30,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "client-x509",
+      "authenticatorFlow" : false,
+      "requirement" : "ALTERNATIVE",
+      "priority" : 40,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "6e54f1be-dbad-4b6d-8eee-8e048d413c63",
+    "alias" : "direct grant",
+    "description" : "OpenID Connect Resource Owner Grant",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "direct-grant-validate-username",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "direct-grant-validate-password",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 30,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Direct Grant - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "31da4b94-03c4-4d79-9ac3-5df1445c0781",
+    "alias" : "docker auth",
+    "description" : "Used by Docker clients to authenticate against the IDP",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "docker-http-basic-authenticator",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "2e16651d-681f-4d9b-9dd4-9acdb465cd43",
+    "alias" : "first broker login",
+    "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticatorConfig" : "review profile config",
+      "authenticator" : "idp-review-profile",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "User creation or linking",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "da109a26-fefa-48a4-ae8e-1d49627c2db8",
+    "alias" : "forms",
+    "description" : "Username, password, otp and other auth forms.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "auth-username-password-form",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Browser - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "4c983c77-241f-41c5-8b8a-e2cd6fc08914",
+    "alias" : "registration",
+    "description" : "registration flow",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "registration-page-form",
+      "authenticatorFlow" : true,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : true,
+      "flowAlias" : "registration form",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "d62c8dd6-633c-408a-aa99-43071510efb4",
+    "alias" : "registration form",
+    "description" : "registration form",
+    "providerId" : "form-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "registration-user-creation",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "registration-password-action",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 50,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "registration-recaptcha-action",
+      "authenticatorFlow" : false,
+      "requirement" : "DISABLED",
+      "priority" : 60,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "c8ca5be7-e76d-4e16-b5ca-3ced99d92dbb",
+    "alias" : "reset credentials",
+    "description" : "Reset credentials for a user if they forgot their password or something",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "reset-credentials-choose-user",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-credential-email",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticator" : "reset-password",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 30,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    }, {
+      "authenticatorFlow" : true,
+      "requirement" : "CONDITIONAL",
+      "priority" : 40,
+      "autheticatorFlow" : true,
+      "flowAlias" : "Reset - Conditional OTP",
+      "userSetupAllowed" : false
+    } ]
+  }, {
+    "id" : "389c1c37-e8af-4610-a507-e1257f55b954",
+    "alias" : "saml ecp",
+    "description" : "SAML ECP Profile Authentication Flow",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "http-basic-authenticator",
+      "authenticatorFlow" : false,
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "autheticatorFlow" : false,
+      "userSetupAllowed" : false
+    } ]
+  } ],
+  "authenticatorConfig" : [ {
+    "id" : "d66ca9d0-1645-4c84-abfe-c0a696f17de4",
+    "alias" : "create unique user config",
+    "config" : {
+      "require.password.update.after.registration" : "false"
+    }
+  }, {
+    "id" : "061cc6b8-90be-4423-9bf9-974ead709b5d",
+    "alias" : "review profile config",
+    "config" : {
+      "update.profile.on.first.login" : "missing"
+    }
+  } ],
+  "requiredActions" : [ {
+    "alias" : "CONFIGURE_TOTP",
+    "name" : "Configure OTP",
+    "providerId" : "CONFIGURE_TOTP",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 10,
+    "config" : { }
+  }, {
+    "alias" : "TERMS_AND_CONDITIONS",
+    "name" : "Terms and Conditions",
+    "providerId" : "TERMS_AND_CONDITIONS",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 20,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PASSWORD",
+    "name" : "Update Password",
+    "providerId" : "UPDATE_PASSWORD",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 30,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PROFILE",
+    "name" : "Update Profile",
+    "providerId" : "UPDATE_PROFILE",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 40,
+    "config" : { }
+  }, {
+    "alias" : "VERIFY_EMAIL",
+    "name" : "Verify Email",
+    "providerId" : "VERIFY_EMAIL",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 50,
+    "config" : { }
+  }, {
+    "alias" : "delete_account",
+    "name" : "Delete Account",
+    "providerId" : "delete_account",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 60,
+    "config" : { }
+  }, {
+    "alias" : "webauthn-register",
+    "name" : "Webauthn Register",
+    "providerId" : "webauthn-register",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 70,
+    "config" : { }
+  }, {
+    "alias" : "webauthn-register-passwordless",
+    "name" : "Webauthn Register Passwordless",
+    "providerId" : "webauthn-register-passwordless",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 80,
+    "config" : { }
+  }, {
+    "alias" : "delete_credential",
+    "name" : "Delete Credential",
+    "providerId" : "delete_credential",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 100,
+    "config" : { }
+  }, {
+    "alias" : "update_user_locale",
+    "name" : "Update User Locale",
+    "providerId" : "update_user_locale",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 1000,
+    "config" : { }
+  } ],
+  "browserFlow" : "browser",
+  "registrationFlow" : "registration",
+  "directGrantFlow" : "direct grant",
+  "resetCredentialsFlow" : "reset credentials",
+  "clientAuthenticationFlow" : "clients",
+  "dockerAuthenticationFlow" : "docker auth",
+  "firstBrokerLoginFlow" : "first broker login",
+  "attributes" : {
+    "cibaBackchannelTokenDeliveryMode" : "poll",
+    "cibaAuthRequestedUserHint" : "login_hint",
+    "clientOfflineSessionMaxLifespan" : "0",
+    "oauth2DevicePollingInterval" : "5",
+    "clientSessionIdleTimeout" : "0",
+    "actionTokenGeneratedByUserLifespan-execute-actions" : "",
+    "actionTokenGeneratedByUserLifespan-verify-email" : "",
+    "clientOfflineSessionIdleTimeout" : "0",
+    "actionTokenGeneratedByUserLifespan-reset-credentials" : "",
+    "cibaInterval" : "5",
+    "realmReusableOtpCode" : "false",
+    "cibaExpiresIn" : "120",
+    "oauth2DeviceCodeLifespan" : "600",
+    "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
+    "parRequestUriLifespan" : "60",
+    "clientSessionMaxLifespan" : "0",
+    "shortVerificationUri" : ""
+  },
+  "keycloakVersion" : "24.0.5",
+  "userManagedAccessAllowed" : false,
+  "clientProfiles" : {
+    "profiles" : [ ]
+  },
+  "clientPolicies" : {
+    "policies" : [ ]
+  }
+}
\ No newline at end of file
diff --git a/dbrepo-auth-service/listeners/target/create-event-listener.jar b/dbrepo-auth-service/listeners/target/create-event-listener.jar
new file mode 100644
index 0000000000000000000000000000000000000000..26cb91c37666c966f6382d35feaaf9f5da5c7f8c
Binary files /dev/null and b/dbrepo-auth-service/listeners/target/create-event-listener.jar differ
diff --git a/dbrepo-auth-service/master-realm.json b/dbrepo-auth-service/master-realm.json
index ef06561e687af0d808781b6c71a1a2b2ea664275..1cf53fe49cffabe7e5833675db95ebff6eec7034 100644
--- a/dbrepo-auth-service/master-realm.json
+++ b/dbrepo-auth-service/master-realm.json
@@ -40,6 +40,7 @@
   "bruteForceProtected" : false,
   "permanentLockout" : false,
   "maxTemporaryLockouts" : 0,
+  "bruteForceStrategy" : "MULTIPLE",
   "maxFailureWaitSeconds" : 900,
   "minimumQuickLoginWaitSeconds" : 60,
   "waitIncrementSeconds" : 60,
@@ -664,8 +665,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
-      "client.use.lightweight.access.token.enabled" : "true"
+      "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
     "fullScopeAllowed" : true,
@@ -783,8 +784,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "realm_client" : "false",
-      "post.logout.redirect.uris" : "+",
       "client.use.lightweight.access.token.enabled" : "true",
+      "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -816,8 +817,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${addressScopeConsentText}"
+      "consent.screen.text" : "${addressScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "4aed5e41-0d8d-4c24-80a0-cd9822072756",
@@ -845,8 +846,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${organizationScopeConsentText}"
+      "consent.screen.text" : "${organizationScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "5e80a7d2-c9d0-48e1-aadc-d8848ff90f92",
@@ -864,6 +865,61 @@
         "jsonType.label" : "String"
       }
     } ]
+  }, {
+    "id" : "1be1e284-2749-4bbb-890a-2d519cc1531c",
+    "name" : "service_account",
+    "description" : "Specific scope for a client enabled for service accounts",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "c913a673-cf66-4493-a2ed-14556c07617c",
+      "name" : "Client ID",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "client_id",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "5c244d68-5c63-4356-ac71-5a586f40c77e",
+      "name" : "Client IP Address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientAddress",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientAddress",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "600285d4-ae51-4b39-a7be-bb83cf5870db",
+      "name" : "Client Host",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientHost",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientHost",
+        "jsonType.label" : "String"
+      }
+    } ]
   }, {
     "id" : "0411ea86-a074-4781-850d-ea3ca94590a2",
     "name" : "offline_access",
@@ -915,8 +971,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${profileScopeConsentText}"
+      "consent.screen.text" : "${profileScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "2d1400be-4053-4393-ba87-91b64f699054",
@@ -1217,8 +1273,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "false",
-      "consent.screen.text" : ""
+      "consent.screen.text" : "",
+      "display.on.consent.screen" : "false"
     },
     "protocolMappers" : [ {
       "id" : "635cbac1-7cab-43bd-99fc-f7084aca2fa2",
@@ -1254,8 +1310,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${rolesScopeConsentText}"
+      "consent.screen.text" : "${rolesScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "2b5a3df4-1adb-402d-bc28-2bd43224e682",
@@ -1264,12 +1320,12 @@
       "protocolMapper" : "oidc-usermodel-realm-role-mapper",
       "consentRequired" : false,
       "config" : {
-        "introspection.token.claim" : "true",
-        "multivalued" : "true",
         "user.attribute" : "foo",
+        "introspection.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "realm_access.roles",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "multivalued" : "true"
       }
     }, {
       "id" : "f3b60071-ef26-48a7-9554-67f62f84d543",
@@ -1278,12 +1334,12 @@
       "protocolMapper" : "oidc-usermodel-client-role-mapper",
       "consentRequired" : false,
       "config" : {
-        "introspection.token.claim" : "true",
-        "multivalued" : "true",
         "user.attribute" : "foo",
+        "introspection.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "resource_access.${client_id}.roles",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "multivalued" : "true"
       }
     }, {
       "id" : "b757200e-494a-4585-857e-e4c18aef7a0c",
@@ -1303,8 +1359,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${emailScopeConsentText}"
+      "consent.screen.text" : "${emailScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "e18769b3-778b-47d8-be52-dd2769deebd1",
@@ -1344,8 +1400,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${phoneScopeConsentText}"
+      "consent.screen.text" : "${phoneScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "98cc724c-3f53-47f7-bf9f-baf2f7e08026",
@@ -1431,7 +1487,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-user-property-mapper" ]
       }
     }, {
       "id" : "4b976576-c880-48a0-9b4d-2956cfd19b4a",
@@ -1440,7 +1496,7 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper" ]
       }
     }, {
       "id" : "e1861ec9-2761-46fb-8048-149492269ff0",
@@ -1470,6 +1526,14 @@
         "allow-default-scopes" : [ "true" ]
       }
     } ],
+    "org.keycloak.userprofile.UserProfileProvider" : [ {
+      "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
+      "providerId" : "declarative-user-profile",
+      "subComponents" : { },
+      "config" : {
+        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
+      }
+    } ],
     "org.keycloak.storage.UserStorageProvider" : [ {
       "id" : "3a6f24e8-128b-4ac1-b3ab-694836db82fd",
       "name" : "Identity Service",
@@ -1483,8 +1547,8 @@
           "config" : {
             "ldap.attribute" : [ "mail" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "false" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "email" ]
           }
         }, {
@@ -1495,8 +1559,8 @@
           "config" : {
             "ldap.attribute" : [ "sn" ],
             "is.mandatory.in.ldap" : [ "true" ],
-            "read.only" : [ "false" ],
             "always.read.value.from.ldap" : [ "true" ],
+            "read.only" : [ "false" ],
             "user.model.attribute" : [ "lastName" ]
           }
         }, {
@@ -1507,8 +1571,8 @@
           "config" : {
             "ldap.attribute" : [ "modifyTimestamp" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "true" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "modifyTimestamp" ]
           }
         }, {
@@ -1541,17 +1605,17 @@
           "providerId" : "group-ldap-mapper",
           "subComponents" : { },
           "config" : {
+            "mode" : [ "LDAP_ONLY" ],
             "membership.attribute.type" : [ "DN" ],
+            "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
             "group.name.ldap.attribute" : [ "cn" ],
+            "ignore.missing.groups" : [ "false" ],
             "membership.user.ldap.attribute" : [ "uid" ],
             "preserve.group.inheritance" : [ "false" ],
-            "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
-            "mode" : [ "LDAP_ONLY" ],
-            "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
             "membership.ldap.attribute" : [ "member" ],
-            "ignore.missing.groups" : [ "false" ],
-            "group.object.classes" : [ "groupOfNames" ],
+            "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
             "memberof.ldap.attribute" : [ "memberOf" ],
+            "group.object.classes" : [ "groupOfNames" ],
             "drop.non.existing.groups.during.sync" : [ "false" ],
             "groups.path" : [ "/" ]
           }
@@ -1563,8 +1627,8 @@
           "config" : {
             "ldap.attribute" : [ "createTimestamp" ],
             "is.mandatory.in.ldap" : [ "false" ],
-            "always.read.value.from.ldap" : [ "true" ],
             "read.only" : [ "true" ],
+            "always.read.value.from.ldap" : [ "true" ],
             "user.model.attribute" : [ "createTimestamp" ]
           }
         } ]
@@ -1580,9 +1644,9 @@
         "importEnabled" : [ "true" ],
         "enabled" : [ "true" ],
         "changedSyncPeriod" : [ "-1" ],
+        "usernameLDAPAttribute" : [ "uid" ],
         "bindCredential" : [ "admin" ],
         "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ],
-        "usernameLDAPAttribute" : [ "uid" ],
         "vendor" : [ "other" ],
         "uuidLDAPAttribute" : [ "entryUUID" ],
         "allowKerberosAuthentication" : [ "false" ],
@@ -1600,14 +1664,6 @@
         "validatePasswordPolicy" : [ "false" ]
       }
     } ],
-    "org.keycloak.userprofile.UserProfileProvider" : [ {
-      "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
-      "providerId" : "declarative-user-profile",
-      "subComponents" : { },
-      "config" : {
-        "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
-      }
-    } ],
     "org.keycloak.keys.KeyProvider" : [ {
       "id" : "5b1052d2-fb71-47d2-86f9-908c869c8d1b",
       "name" : "hmac-generated-hs512",
@@ -2219,10 +2275,12 @@
     "parRequestUriLifespan" : "60",
     "clientSessionMaxLifespan" : "0",
     "frontendUrl" : "",
+    "organizationsEnabled" : "false",
     "acr.loa.map" : "{}"
   },
-  "keycloakVersion" : "24.0.5",
+  "keycloakVersion" : "26.0.4",
   "userManagedAccessAllowed" : false,
+  "organizationsEnabled" : false,
   "clientProfiles" : {
     "profiles" : [ ]
   },
diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile
index 4b45e9429050c08bcf4c3fd42b3d0ab259801657..9edf1375fb6c47f63dbd45f26bba0b3a6fe15255 100644
--- a/dbrepo-data-service/Dockerfile
+++ b/dbrepo-data-service/Dockerfile
@@ -8,7 +8,7 @@ LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 
 COPY ./pom.xml ./
 
-RUN mvn -fn -B -q dependency:go-offline
+RUN mvn -fn dependency:go-offline
 
 COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien
 
@@ -18,7 +18,7 @@ COPY ./rest-service ./rest-service
 COPY ./services ./services
 
 # Make sure it compiles
-RUN mvn -fn -B -q clean package -DskipTests
+RUN mvn -fn clean package -DskipTests
 
 ###### THIRD STAGE ######
 FROM amazoncorretto:17-alpine3.19 AS runtime
diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml
index 7d5e6941e4fc89f481e9724ac27d246f2b3fa979..e2bfa739618b3a518aeabd623ea49718b9a06d5b 100644
--- a/dbrepo-data-service/pom.xml
+++ b/dbrepo-data-service/pom.xml
@@ -11,7 +11,7 @@
     <groupId>at.tuwien</groupId>
     <artifactId>dbrepo-data-service</artifactId>
     <name>dbrepo-data-service</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <description>Service that manages the data</description>
 
diff --git a/dbrepo-data-service/querystore/pom.xml b/dbrepo-data-service/querystore/pom.xml
index cb712233ce0743cf684af6a7e5efaf2d7937cea5..2905b5a935407cab65086def3f9c21d980ee329a 100644
--- a/dbrepo-data-service/querystore/pom.xml
+++ b/dbrepo-data-service/querystore/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-data-service-querystore</artifactId>
     <name>dbrepo-data-service-querystore</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies/>
 
diff --git a/dbrepo-data-service/report/pom.xml b/dbrepo-data-service/report/pom.xml
index 8de452bbf069bad2795233a79019222eabdcb6b3..4b230d55ebfbf084cfd00eea7cd7c568ac620d71 100644
--- a/dbrepo-data-service/report/pom.xml
+++ b/dbrepo-data-service/report/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>report</artifactId>
     <name>dbrepo-data-service-report</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
     <description>
         This module is only intended for the pipeline coverage report. See the detailed report in the
         respective modules
diff --git a/dbrepo-data-service/rest-service/pom.xml b/dbrepo-data-service/rest-service/pom.xml
index 8ff195ea791a9da6e2ceddd20ab2da5ddc9fdafc..721cf1a254c8fff0927bffbd7d6ff27b3dcead8d 100644
--- a/dbrepo-data-service/rest-service/pom.xml
+++ b/dbrepo-data-service/rest-service/pom.xml
@@ -6,18 +6,18 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>rest-service</artifactId>
     <name>dbrepo-data-service-rest-service</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
             <groupId>at.tuwien</groupId>
             <artifactId>services</artifactId>
-            <version>1.6.2</version>
+            <version>1.6.3</version>
         </dependency>
     </dependencies>
 
@@ -38,6 +38,14 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>9</source>
+                    <target>9</target>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
index d4eccd0772eba12e007c6e99ae42a60b1304fca5..25dfd50dd434df444a45c4f7850fcdd803f0e9de 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
@@ -214,7 +214,7 @@ public class ViewEndpoint extends RestEndpoint {
     @RequestMapping(value = "/{viewId}/data", method = {RequestMethod.GET, RequestMethod.HEAD})
     @Observed(name = "dbrepo_view_data")
     @Operation(summary = "Get view data",
-            description = "Gets data from a view of a database. For private databases, the user needs at least *READ* access to the associated database. Requires role `view-database-view-data`.",
+            description = "Gets data from a view of a database. For private databases, the user needs at least *READ* access to the associated database.",
             security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "200",
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
index 5dce4988561b2bf653c77358701ccfba674d6269..b003ebfb4fd427c0b6bd92aef0595915f5c2bdbd 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
@@ -330,17 +330,17 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         when(httpServletRequest.getMethod())
                 .thenReturn("GET");
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_1_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL);
+            viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL);
         });
     }
 
@@ -366,15 +366,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_3_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_3_PRINCIPAL);
+            viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL);
         });
     }
 
@@ -384,15 +384,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_3_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_3_ID, null, USER_3_PRINCIPAL);
+            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL);
         });
     }
 
@@ -418,15 +418,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             NotAllowedException, MetadataServiceException {
 
         /* mock */
-        when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
-                .thenReturn(VIEW_3_PRIVILEGED_DTO);
+        when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
+                .thenReturn(VIEW_1_PRIVILEGED_DTO);
         doThrow(NotAllowedException.class)
                 .when(credentialService)
-                .getAccess(DATABASE_1_ID, USER_1_ID);
+                .getAccess(DATABASE_1_ID, USER_4_ID);
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
-            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_3_ID, null, USER_1_PRINCIPAL);
+            viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL);
         });
     }
 
diff --git a/dbrepo-data-service/services/pom.xml b/dbrepo-data-service/services/pom.xml
index d0fe72cbeba104d992c2325ddf7813eb00c3c663..04ddee3c59536698ac1fb63cd094f93410941328 100644
--- a/dbrepo-data-service/services/pom.xml
+++ b/dbrepo-data-service/services/pom.xml
@@ -6,18 +6,18 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-data-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>services</artifactId>
     <name>dbrepo-data-service-services</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
             <groupId>at.tuwien</groupId>
             <artifactId>dbrepo-data-service-querystore</artifactId>
-            <version>1.6.2</version>
+            <version>1.6.3</version>
         </dependency>
     </dependencies>
 
diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf
index fd66cf805ef4bc7d5e7bb5e93ee54381015e88f6..68778de757bf331e183e7258755c6f3ef210d6ec 100644
--- a/dbrepo-gateway-service/dbrepo.conf
+++ b/dbrepo-gateway-service/dbrepo.conf
@@ -40,6 +40,10 @@ upstream dashboard-service {
     server dashboard-service:3000;
 }
 
+upstream auth-service {
+    server auth-service:8080;
+}
+
 server {
     listen 8080 default_server;
     server_name _;
@@ -67,6 +71,26 @@ server {
         proxy_read_timeout      90;
     }
 
+    # Proxy Keycloak OIDC connections, c.f. https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations
+    location /realms {
+        proxy_set_header        Host $host;
+        proxy_set_header        X-Real-IP $remote_addr;
+        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header        X-Forwarded-Proto $scheme;
+        proxy_pass              http://auth-service;
+        proxy_read_timeout      90;
+    }
+
+    # Proxy Keycloak assets, c.f. https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations
+    location /resources {
+        proxy_set_header        Host $host;
+        proxy_set_header        X-Real-IP $remote_addr;
+        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header        X-Forwarded-Proto $scheme;
+        proxy_pass              http://auth-service;
+        proxy_read_timeout      90;
+    }
+
     location /api/search {
         proxy_set_header        Host $host;
         proxy_set_header        X-Real-IP $remote_addr;
diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql
index c9ce89d1be71f4791c5e55dbb7c24f46e979355a..e2bde25ed6d64f69c4f8d6e897a49a672e3f9a71 100644
--- a/dbrepo-metadata-db/1_setup-schema.sql
+++ b/dbrepo-metadata-db/1_setup-schema.sql
@@ -3,10 +3,10 @@ BEGIN;
 CREATE TABLE IF NOT EXISTS `mdb_users`
 (
     id               character varying(36)  NOT NULL,
+    keycloak_id      character varying(36)  NOT NULL,
     username         character varying(255) NOT NULL,
     firstname        character varying(255),
     lastname         character varying(255),
-    email            character varying(255) NOT NULL,
     orcid            character varying(255),
     affiliation      character varying(255),
     is_internal      BOOLEAN                NOT NULL DEFAULT FALSE,
@@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS `mdb_users`
     theme            character varying(255) NOT NULL default ('light'),
     language         character varying(3)   NOT NULL default ('en'),
     PRIMARY KEY (id),
-    UNIQUE (username),
-    UNIQUE (email)
+    UNIQUE (keycloak_id),
+    UNIQUE (username)
 ) WITH SYSTEM VERSIONING;
 
 CREATE TABLE IF NOT EXISTS `mdb_images`
diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile
index ddc20cb420764196c3a4b423294200e26eaa5bce..fa92b799eeaac75f9daea7b5a1eec11560b04647 100644
--- a/dbrepo-metadata-service/Dockerfile
+++ b/dbrepo-metadata-service/Dockerfile
@@ -12,7 +12,7 @@ COPY ./rest-service/pom.xml ./rest-service/
 COPY ./services/pom.xml ./services/
 COPY ./test/pom.xml ./test/
 
-RUN mvn -fn -B dependency:go-offline
+RUN mvn dependency:go-offline
 
 COPY ./api ./api
 COPY ./entities ./entities
@@ -24,7 +24,7 @@ COPY ./services ./services
 COPY ./test ./test
 
 # Make sure it compiles
-RUN mvn -fn -B clean install -DskipTests
+RUN mvn clean install -DskipTests
 
 ###### SECOND STAGE ######
 FROM amazoncorretto:17-alpine3.19 AS runtime
diff --git a/dbrepo-metadata-service/api/pom.xml b/dbrepo-metadata-service/api/pom.xml
index c1e74c5ae9a6f747d8180fc512aaf0f23b03e650..0d534105f8a12d52201e2437d31360903292f657 100644
--- a/dbrepo-metadata-service/api/pom.xml
+++ b/dbrepo-metadata-service/api/pom.xml
@@ -6,18 +6,18 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-api</artifactId>
     <name>dbrepo-metadata-service-api</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
             <groupId>at.tuwien</groupId>
             <artifactId>dbrepo-metadata-service-entities</artifactId>
-            <version>1.6.2</version>
+            <version>1.6.3</version>
             <scope>compile</scope>
         </dependency>
     </dependencies>
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
index a30208bad0c577af2e80c9d629b087bdf5b3e7e7..16f45aec4d625639f1188e0e853b3a81bd71811f 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java
@@ -1,13 +1,14 @@
 package at.tuwien.api.auth;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.Email;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
 
+import java.util.UUID;
+
 @Getter
 @Setter
 @Builder
@@ -18,18 +19,28 @@ import lombok.extern.jackson.Jacksonized;
 @ToString
 public class CreateUserDto {
 
+    @NotNull
+    @Schema(example = "3b91bc36-3eae-4662-a4be-8993624ab0cb", description = "The user id generated by Keycloak")
+    private UUID id;
+
+    @NotNull
+    @JsonProperty("ldap_id")
+    @Schema(example = "ea022d6d-b4a4-42f3-836f-ff4e596a527a", description = "The user id generated by OpenLDAP")
+    private UUID ldapId;
+
     @NotBlank
-    @Pattern(regexp = "^[a-z0-9]{3,}$")
     @Schema(example = "user")
     private String username;
 
-    @NotBlank
-    @Email
-    @Schema(example = "user@example.com")
-    private String email;
+    @JsonProperty("given_name")
+    @Schema(example = "foo")
+    private String givenName;
 
-    @NotNull
-    @ToString.Exclude
-    private String password;
+    @JsonProperty("family_name")
+    @Schema(example = "bar")
+    private String familyName;
+
+    @Schema(example = "foo.bar@example.com")
+    private String email;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
index 97f35026747aaf86f33b714dc83b1b3f173dda2f..f94edc2cf75421855a8bcd761252e6aba249bb27 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java
@@ -50,6 +50,9 @@ public class IdentifierBriefDto {
     @NotNull
     private List<IdentifierTitleDto> titles;
 
+    @NotNull
+    private List<IdentifierDescriptionDto> descriptions;
+
     @Schema(example = "10.1038/nphys1170")
     private String doi;
 
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..26d700e798e1517ae484dc60e9359bd8b5646965
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java
@@ -0,0 +1,26 @@
+package at.tuwien.api.keycloak;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class ModifyUserDto {
+
+    @JsonProperty("firstName")
+    private String firstname;
+
+    @JsonProperty("lastName")
+    private String lastname;
+
+    @NotNull
+    private UserAttributesDto attributes;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java
index 027955ba77b69fd708c1c18463c1a92d09c93c95..50718bc8034d500c2d707abacac58acf2bb95012 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java
@@ -16,12 +16,20 @@ import java.util.UUID;
 @ToString
 public class UserAttributesDto {
 
-    @Schema(example = "s3cr3t")
-    @JsonProperty("LDAP_ENTRY_DN")
-    private String[] ldapEntryDn;
+    @Schema(example = "dark")
+    @JsonProperty("THEME")
+    private String[] theme;
 
-    @Schema(example = "false")
-    @JsonProperty("LDAP_ID")
-    private UUID[] ldapId;
+    @Schema(example = "en")
+    @JsonProperty("LANGUAGE")
+    private String[] language;
+
+    @Schema(example = "https://ror.org/04d836q62")
+    @JsonProperty("AFFILIATION")
+    private String[] affiliation;
+
+    @Schema(example = "https://orcid.org/0000-0003-4216-302X")
+    @JsonProperty("ORCID")
+    private String[] orcid;
 
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java
deleted file mode 100644
index a2d7811ab0aa334a4f3a5d49916428b58166317b..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package at.tuwien.api.keycloak;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-import lombok.*;
-import lombok.extern.jackson.Jacksonized;
-
-import java.util.UUID;
-
-@Getter
-@Setter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Jacksonized
-@ToString
-public class UserDto {
-
-    @NotNull
-    private UUID id;
-
-    @NotNull
-    @Schema(example = "jcarberry", description = "Only contains lowercase characters")
-    private String username;
-
-    @NotNull
-    @Schema(example = "true")
-    private Boolean enabled;
-
-    @NotNull
-    @Schema(example = "false")
-    private Boolean totp;
-
-    @NotNull
-    @JsonProperty("emailVerified")
-    @Schema(example = "false")
-    private Boolean emailVerified;
-
-    @NotNull
-    @Schema(example = "jcarberry@brown.edu")
-    private String email;
-
-    @NotNull
-    @JsonProperty("notBefore")
-    @Schema(example = "0")
-    private Long notBefore;
-
-    @NotNull
-    private UserAttributesDto attributes;
-
-}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..3155d75f027d2864f2a06ecf19376c13c9be7d35
--- /dev/null
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java
@@ -0,0 +1,27 @@
+package at.tuwien.api.keycloak;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.extern.jackson.Jacksonized;
+
+import java.util.UUID;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Jacksonized
+@ToString
+public class UserIdAttributesDto {
+
+    @Schema(example = "s3cr3t")
+    @JsonProperty("LDAP_ENTRY_DN")
+    private String[] ldapEntryDn;
+
+    @Schema(example = "false")
+    @JsonProperty("LDAP_ID")
+    private UUID[] ldapId;
+
+}
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java
index 78b87e33212ab48ba2e37a583100eea780c459e7..f883a034f55bd5f04d3059f8eb50ef50a3867c79 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java
@@ -1,5 +1,6 @@
 package at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated;
 
 public enum OrcidDisambiguatedSourceTypeDto {
-    RINGGOLD
+    RINGGOLD,
+    ROR
 }
diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
index cd5e8fd3e0cefe2f016261470b1236e9a3442b16..2ab170d616c75c40d4be36af42854d518d3ec7c5 100644
--- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
+++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
@@ -1,6 +1,5 @@
 package at.tuwien.api.user;
 
-import jakarta.validation.constraints.Email;
 import jakarta.validation.constraints.NotNull;
 import lombok.*;
 import lombok.extern.jackson.Jacksonized;
@@ -30,10 +29,6 @@ public class UserDetailsDto implements UserDetails {
     @ToString.Exclude
     private String password;
 
-    @NotNull
-    @Email
-    private String email;
-
     @Override
     public boolean isAccountNonExpired() {
         return true;
diff --git a/dbrepo-metadata-service/entities/pom.xml b/dbrepo-metadata-service/entities/pom.xml
index 9252dd2caa13505becc99e347759de5923cd7fc8..1967b24868d61e29351b34c8608c6f428bc316f9 100644
--- a/dbrepo-metadata-service/entities/pom.xml
+++ b/dbrepo-metadata-service/entities/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-entities</artifactId>
     <name>dbrepo-metadata-service-entity</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies/>
 
diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java
index fd87852c6ecce0e2e614a9c7dd05a5e41cfe2e16..ba86e3d29c6913d45d51ae0498fdac8d3092b657 100644
--- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java
+++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java
@@ -30,6 +30,10 @@ public class User {
     @Column(name = "ID", nullable = false, columnDefinition = "VARCHAR(36)")
     private UUID id;
 
+    @JdbcTypeCode(java.sql.Types.VARCHAR)
+    @Column(name = "keycloak_id", nullable = false, columnDefinition = "VARCHAR(36)")
+    private UUID keycloakId;
+
     @Column(nullable = false)
     private String username;
 
@@ -39,9 +43,6 @@ public class User {
     @Column
     private String lastname;
 
-    @Column(nullable = false)
-    private String email;
-
     @Column
     private String orcid;
 
diff --git a/dbrepo-metadata-service/metrics.md b/dbrepo-metadata-service/metrics.md
index 56a69c68f6913ab2e3ea192cde66f329ea336e10..f3e0a3130f23e149a54f1eca8247c559443809da 100644
--- a/dbrepo-metadata-service/metrics.md
+++ b/dbrepo-metadata-service/metrics.md
@@ -59,8 +59,6 @@
 | `dbrepo_user_find`                 | Get user                      |
 | `dbrepo_user_modify`               | Update user                   |
 | `dbrepo_user_password_modify`      | Update user password          |
-| `dbrepo_user_refresh_token`        | Refresh token                 |
-| `dbrepo_user_token`                | Create token                  |
 | `dbrepo_users_list`                | List users                    |
 | `dbrepo_view_create`               | Create view                   |
 | `dbrepo_view_delete`               | Delete view                   |
diff --git a/dbrepo-metadata-service/oai/pom.xml b/dbrepo-metadata-service/oai/pom.xml
index 87da814d4152dc1a3398ee67cf4662d1d188519b..b6db9e69674d52ae557644b94b7eb5302563c86f 100644
--- a/dbrepo-metadata-service/oai/pom.xml
+++ b/dbrepo-metadata-service/oai/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-oai</artifactId>
     <name>dbrepo-metadata-service-oai</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies/>
 
diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml
index 04af8a795f25072c5756489d3b7c42a1828c6b59..5dd6ce3318f7cb88a16c9c6ecc60c8d4c5ff5aa2 100644
--- a/dbrepo-metadata-service/pom.xml
+++ b/dbrepo-metadata-service/pom.xml
@@ -11,7 +11,7 @@
     <groupId>at.tuwien</groupId>
     <artifactId>dbrepo-metadata-service</artifactId>
     <name>dbrepo-metadata-service</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <description>Service that manages the metadata</description>
 
@@ -27,7 +27,7 @@
         <module>report</module>
     </modules>
 
-    <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/</url>
+    <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url>
     <developers>
         <developer>
             <name>Martin Weise</name>
@@ -52,7 +52,7 @@
         <apache-jena.version>4.10.0</apache-jena.version>
         <opencsv.version>5.7.1</opencsv.version>
         <super-csv.version>2.4.0</super-csv.version>
-        <keycloak.version>21.0.2</keycloak.version>
+        <keycloak.version>26.0.4</keycloak.version>
         <springdoc-openapi.version>2.3.0</springdoc-openapi.version>
         <testcontainers.version>1.19.1</testcontainers.version>
         <jackson.version>2.15.2</jackson.version>
@@ -187,6 +187,11 @@
             <artifactId>keycloak-common</artifactId>
             <version>${keycloak.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-admin-client</artifactId>
+            <version>${keycloak.version}</version>
+        </dependency>
         <dependency>
             <groupId>com.auth0</groupId>
             <artifactId>java-jwt</artifactId>
diff --git a/dbrepo-metadata-service/report/pom.xml b/dbrepo-metadata-service/report/pom.xml
index 756681f202dde19b48c70187003ff8c7270066be..8d4d32c15d3e50cb65ba2300c58d25dcbb87eebd 100644
--- a/dbrepo-metadata-service/report/pom.xml
+++ b/dbrepo-metadata-service/report/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-report</artifactId>
     <name>dbrepo-metadata-service-report</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/repositories/pom.xml b/dbrepo-metadata-service/repositories/pom.xml
index 39e971b901c27abdd87fda9a25dbb41bdc999c0c..57f89e7ed46587a564e57536d05b79fc1e5cb121 100644
--- a/dbrepo-metadata-service/repositories/pom.xml
+++ b/dbrepo-metadata-service/repositories/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-repositories</artifactId>
     <name>dbrepo-metadata-service-repositories</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
index ac6cacf64f007440e26df82d86eb6d1302f27390..cfbf858000ae4b2e58be5999c3c98123cc70582c 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java
@@ -1,6 +1,5 @@
 package at.tuwien.mapper;
 
-import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.container.ContainerBriefDto;
 import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.container.CreateContainerDto;
@@ -13,14 +12,14 @@ import at.tuwien.api.database.*;
 import at.tuwien.api.database.table.TableBriefDto;
 import at.tuwien.api.database.table.TableDto;
 import at.tuwien.api.database.table.columns.ColumnBriefDto;
-import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.ColumnDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.concepts.ConceptDto;
 import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto;
 import at.tuwien.api.database.table.columns.concepts.UnitDto;
 import at.tuwien.api.database.table.columns.concepts.UnitSaveDto;
-import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import at.tuwien.api.database.table.constraints.ConstraintsDto;
+import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto;
 import at.tuwien.api.database.table.constraints.foreign.ForeignKeyBriefDto;
 import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto;
 import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto;
@@ -31,9 +30,7 @@ import at.tuwien.api.datacite.doi.*;
 import at.tuwien.api.identifier.*;
 import at.tuwien.api.identifier.ld.LdCreatorDto;
 import at.tuwien.api.identifier.ld.LdDatasetDto;
-import at.tuwien.api.keycloak.CredentialDto;
-import at.tuwien.api.keycloak.CredentialTypeDto;
-import at.tuwien.api.keycloak.UpdateCredentialsDto;
+import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.api.keycloak.UserCreateDto;
 import at.tuwien.api.maintenance.BannerMessageBriefDto;
 import at.tuwien.api.maintenance.BannerMessageCreateDto;
@@ -50,8 +47,8 @@ import at.tuwien.api.semantics.OntologyBriefDto;
 import at.tuwien.api.semantics.OntologyCreateDto;
 import at.tuwien.api.semantics.OntologyDto;
 import at.tuwien.api.user.UserBriefDto;
-import at.tuwien.api.user.UserDetailsDto;
 import at.tuwien.api.user.UserDto;
+import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.api.user.external.ExternalMetadataDto;
 import at.tuwien.api.user.external.ExternalResultType;
 import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto;
@@ -74,6 +71,8 @@ import at.tuwien.entities.maintenance.BannerMessage;
 import at.tuwien.entities.maintenance.BannerMessageType;
 import at.tuwien.entities.semantics.Ontology;
 import at.tuwien.entities.user.User;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.mapstruct.*;
 
 import java.text.Normalizer;
@@ -97,6 +96,16 @@ public interface MetadataMapper {
     })
     DataTypeDto dataTypeToDataTypeDto(DataType data);
 
+    @Mappings({
+            @Mapping(target = "attributes", ignore = true)
+    })
+    UserRepresentation userCreateDtoToUserRepresentation(UserCreateDto data);
+
+    @Mappings({
+            @Mapping(target = "accessToken", source = "token")
+    })
+    TokenDto accessTokenResponseToTokenDto(AccessTokenResponse data);
+
     BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data);
 
     BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data);
@@ -112,6 +121,16 @@ public interface MetadataMapper {
     })
     Container containerCreateRequestDtoToContainer(CreateContainerDto data);
 
+    UserUpdateDto userToUserUpdateDto(User data);
+
+    default List<String> optionalValueToMap(String value) {
+        final List<String> attr = new LinkedList<>();
+        if (value != null) {
+            attr.add(value);
+        }
+        return attr;
+    }
+
     ContainerDto containerToContainerDto(Container data);
 
     @Mappings({
@@ -395,6 +414,8 @@ public interface MetadataMapper {
 
     IdentifierType identifierTypeDtoToIdentifierType(IdentifierTypeDto data);
 
+    IdentifierStatusType identifierStatusTypeDtoToIdentifierStatusType(IdentifierStatusTypeDto data);
+
     default String identifierToLocationUrl(String baseUrl, Identifier data) {
         if (data.getType().equals(IdentifierType.SUBSET)) {
             return baseUrl + "/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/info?pid=" + data.getId();
@@ -536,8 +557,6 @@ public interface MetadataMapper {
     }
 
     default TableDto tableToTableDto(Table data) {
-        data.getDatabase()
-                .setTables(null);
         final TableDto table = TableDto.builder()
                 .id(data.getId())
                 .name(data.getName())
@@ -550,7 +569,10 @@ public interface MetadataMapper {
                 .description(data.getDescription())
                 .identifiers(new LinkedList<>())
                 .columns(new LinkedList<>())
-                .database(databaseToDatabaseDto(data.getDatabase()))
+                .database(databaseToDatabaseDto(data.getDatabase()
+                        .toBuilder()
+                        .tables(null)
+                        .build()))
                 .constraints(constraintsToConstraintsDto(data.getConstraints()))
                 .build();
         if (data.getIdentifiers() != null) {
@@ -746,40 +768,6 @@ public interface MetadataMapper {
     })
     TableColumn columnCreateDtoToTableColumn(CreateTableColumnDto data, ContainerImage image);
 
-    default UpdateCredentialsDto passwordToUpdateCredentialsDto(String password) {
-        return UpdateCredentialsDto.builder()
-                .credentials(List.of(CredentialDto.builder()
-                        .temporary(false)
-                        .type(CredentialTypeDto.PASSWORD)
-                        .value(password)
-                        .build()))
-                .build();
-    }
-
-    default UserCreateDto signupRequestDtoToUserCreateDto(CreateUserDto data) {
-        return UserCreateDto.builder()
-                .username(data.getUsername())
-                .email(data.getEmail())
-                .credentials(List.of(CredentialDto.builder()
-                        .type(CredentialTypeDto.PASSWORD)
-                        .temporary(false)
-                        .value(data.getPassword())
-                        .build()))
-                .enabled(true)
-                .build();
-    }
-
-    /* keep */
-    UserBriefDto keycloakUserDtoToUserBriefDto(at.tuwien.api.keycloak.UserDto data);
-
-    /* keep */
-    @Mappings({
-            @Mapping(target = "id", expression = "java(data.getId().toString())")
-    })
-    UserDetailsDto userDtoToUserDetailsDto(UserDto data);
-
-    User userDtoToUser(at.tuwien.api.keycloak.UserDto data);
-
     /* keep */
     @Mappings({
             @Mapping(target = "name", expression = "java(userToFullName(data))"),
@@ -787,8 +775,6 @@ public interface MetadataMapper {
     })
     UserBriefDto userToUserBriefDto(User data);
 
-    UserBriefDto userDtoToUserBriefDto(UserDto data);
-
     /* keep */
     @Mappings({
             @Mapping(target = "attributes.language", source = "language"),
@@ -801,9 +787,6 @@ public interface MetadataMapper {
     })
     UserDto userToUserDto(User data);
 
-    /* keep */
-    User userDtoToUserDto(UserDto data);
-
     /* keep */
     @Named("userToFullName")
     default String userToFullName(User data) {
@@ -837,7 +820,8 @@ public interface MetadataMapper {
     }
 
     @Mappings({
-            @Mapping(target = "database.views", ignore = true)
+            @Mapping(target = "database.views", ignore = true),
+            @Mapping(target = "database.tables", ignore = true)
     })
     ViewDto viewToViewDto(View data);
 
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java
index 7415fb422c03882f7f71786b0edf756c7bd58159..30f2f20c1670f550f7463265f1d2d6afde967777 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java
@@ -17,7 +17,5 @@ public interface UserRepository extends JpaRepository<User, UUID> {
 
     boolean existsByUsername(String username);
 
-    boolean existsByEmail(String email);
-
 }
 
diff --git a/dbrepo-metadata-service/rest-service/pom.xml b/dbrepo-metadata-service/rest-service/pom.xml
index 9f8055a149d1b6f1ca03bf03d69daba0cbce82a2..ff5966688771f30a93b2ce4d95bc99ab6aa0a83f 100644
--- a/dbrepo-metadata-service/rest-service/pom.xml
+++ b/dbrepo-metadata-service/rest-service/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-rest-service</artifactId>
     <name>dbrepo-metadata-service-rest</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bdb80973176bc7ae5722b932e7f7b1a2a183d45
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java
@@ -0,0 +1,16 @@
+package at.tuwien.config;
+
+import at.tuwien.converters.IdentifierStatusTypeDtoConverter;
+import at.tuwien.converters.IdentifierTypeDtoConverter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.format.FormatterRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class MvcConfig implements WebMvcConfigurer {
+    @Override
+    public void addFormatters(FormatterRegistry registry) {
+        registry.addConverter(new IdentifierStatusTypeDtoConverter());
+        registry.addConverter(new IdentifierTypeDtoConverter());
+    }
+}
\ No newline at end of file
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..96e67f63d2bb85bb0aaebd02237a2d8aaa6ecdfa
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java
@@ -0,0 +1,14 @@
+package at.tuwien.converters;
+
+import at.tuwien.api.identifier.IdentifierStatusTypeDto;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class IdentifierStatusTypeDtoConverter implements Converter<String, IdentifierStatusTypeDto> {
+
+    @Override
+    public IdentifierStatusTypeDto convert(String source) {
+        return IdentifierStatusTypeDto.valueOf(source.toUpperCase());
+    }
+}
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java
similarity index 79%
rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java
rename to dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java
index b3f52c4377989a1380c6be42b46ce96f1d902163..61e169604fa2cf1e10c464fdb1d1bc310ea7f125 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java
@@ -5,7 +5,7 @@ import org.springframework.core.convert.converter.Converter;
 import org.springframework.stereotype.Component;
 
 @Component
-public class IdentifierTypeConverter implements Converter<String, IdentifierTypeDto> {
+public class IdentifierTypeDtoConverter implements Converter<String, IdentifierTypeDto> {
 
     @Override
     public IdentifierTypeDto convert(String source) {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
index 6ee9fa6c9e4a3e7b7d9882197e8a835eca8e6f9c..50016103d83ccfffab65ddc153e6b88074e34e2c 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java
@@ -194,7 +194,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
             @ApiResponse(responseCode = "404",
-                    description = "Failed to fin user/database in metadata database",
+                    description = "Failed to find database in metadata database",
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
@@ -211,7 +211,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<DatabaseBriefDto> refreshTableMetadata(@NotNull @PathVariable("databaseId") Long databaseId,
                                                                  @NotNull Principal principal) throws DataServiceException,
-            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, UserNotFoundException,
+            DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException,
             SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, MalformedException,
             TableNotFoundException {
         log.debug("endpoint refresh database metadata, databaseId={}", databaseId);
@@ -513,7 +513,7 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                     .findFirst();
             if (!database.getIsPublic() && !database.getIsSchemaPublic() && optional.isEmpty() && !isSystem(principal)) {
                 log.error("Failed to find database: not public and no access found");
-                throw new DatabaseNotFoundException("Failed to find database: not public and no access found");
+                throw new NotAllowedException("Failed to find database: not public and no access found");
             }
             /* reduce metadata */
             database.setTables(database.getTables()
@@ -534,14 +534,16 @@ public class DatabaseEndpoint extends AbstractEndpoint {
                 throw new NotAllowedException("Failed to find database: not public and not authenticated");
             }
             /* reduce metadata */
-            database.setTables(database.getTables()
-                    .stream()
-                    .filter(t -> t.getIsPublic() || t.getIsSchemaPublic())
-                    .toList());
-            database.setViews(database.getViews()
-                    .stream()
-                    .filter(v -> v.getIsPublic() || v.getIsSchemaPublic())
-                    .toList());
+            database.getTables()
+                    .removeAll(database.getTables()
+                            .stream()
+                            .filter(t -> !t.getIsPublic() && !t.getIsSchemaPublic())
+                            .toList());
+            database.getViews()
+                    .removeAll(database.getViews()
+                            .stream()
+                            .filter(v -> !v.getIsPublic() && !v.getIsSchemaPublic())
+                            .toList());
             database.setAccesses(List.of());
         }
         final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database);
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
index b70516fa66e8476fa65cb9d50ab750976394da9f..b3d699086ee93b943801a3139a2e2488dc9dcc8c 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java
@@ -73,7 +73,7 @@ public class IdentifierEndpoint extends AbstractEndpoint {
         this.identifierService = identifierService;
     }
 
-    @GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json"})
+    @GetMapping
     @Transactional(readOnly = true)
     @Observed(name = "dbrepo_identifier_list")
     @Operation(summary = "List identifiers",
@@ -87,48 +87,41 @@ public class IdentifierEndpoint extends AbstractEndpoint {
                             @Content(mediaType = "application/ld+json",
                                     array = @ArraySchema(schema = @Schema(implementation = LdDatasetDto.class)))
                     }),
-            @ApiResponse(responseCode = "406",
-                    description = "Identifier could not be exported, the requested style is not known",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
     })
-    public ResponseEntity<?> findAll(@Valid @RequestParam(value = "dbid", required = false) Long dbid,
+    public ResponseEntity<?> findAll(@Valid @RequestParam(value = "type", required = false) IdentifierTypeDto type,
+                                     @Valid @RequestParam(value = "status", required = false) IdentifierStatusTypeDto status,
+                                     @Valid @RequestParam(value = "dbid", required = false) Long dbid,
                                      @Valid @RequestParam(value = "qid", required = false) Long qid,
                                      @Valid @RequestParam(value = "vid", required = false) Long vid,
                                      @Valid @RequestParam(value = "tid", required = false) Long tid,
-                                     @RequestHeader(HttpHeaders.ACCEPT) String accept)
-            throws FormatNotAvailableException {
-        log.debug("endpoint find identifiers, dbid={}, qid={}, vid={}, tid={}, accept={}", dbid, qid, vid, tid, accept);
+                                     @RequestHeader(HttpHeaders.ACCEPT) String accept,
+                                     Principal principal) {
+        log.debug("endpoint find identifiers, type={}, status={}, dbid={}, qid={}, vid={}, tid={}, accept={}", type,
+                status, dbid, qid, vid, tid, accept);
         final List<Identifier> identifiers = identifierService.findAll()
                 .stream()
+                .filter(i -> !Objects.nonNull(type) || metadataMapper.identifierTypeDtoToIdentifierType(type).equals(i.getType()))
+                .filter(i -> !Objects.nonNull(status) || metadataMapper.identifierStatusTypeDtoToIdentifierStatusType(status).equals(i.getStatus()))
                 .filter(i -> !Objects.nonNull(dbid) || dbid.equals(i.getDatabase().getId()))
                 .filter(i -> !Objects.nonNull(qid) || qid.equals(i.getQueryId()))
                 .filter(i -> !Objects.nonNull(vid) || vid.equals(i.getViewId()))
                 .filter(i -> !Objects.nonNull(tid) || tid.equals(i.getTableId()))
+                .filter(i -> principal != null && i.getStatus().equals(IdentifierStatusType.DRAFT) ? i.getOwnedBy().equals(getId(principal)) : i.getStatus().equals(IdentifierStatusType.PUBLISHED))
                 .toList();
         if (identifiers.isEmpty()) {
             return ResponseEntity.ok(List.of());
         }
         log.trace("found persistent identifiers {}", identifiers);
-        return switch (accept) {
-            case "application/json" -> {
-                log.trace("accept header matches json");
-                yield ResponseEntity.ok(identifiers.stream()
-                        .map(metadataMapper::identifierToIdentifierBriefDto)
-                        .toList());
-            }
-            case "application/ld+json" -> {
-                log.trace("accept header matches json-ld");
-                yield ResponseEntity.ok(identifiers.stream()
-                        .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl()))
-                        .toList());
-            }
-            default -> {
-                log.error("accept header {} is not supported", accept);
-                throw new FormatNotAvailableException("Must provide either application/json or application/ld+json headers");
-            }
-        };
+        if (accept.equals("application/ld+json")) {
+            log.trace("accept header matches json-ld");
+            return ResponseEntity.ok(identifiers.stream()
+                    .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl()))
+                    .toList());
+        }
+        log.trace("default to json");
+        return ResponseEntity.ok(identifiers.stream()
+                .map(metadataMapper::identifierToIdentifierBriefDto)
+                .toList());
     }
 
     @GetMapping(value = "/{identifierId}", produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json",
@@ -156,6 +149,11 @@ public class IdentifierEndpoint extends AbstractEndpoint {
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "403",
+                    description = "Not allowed to view identifier",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
             @ApiResponse(responseCode = "404",
                     description = "Identifier could not be found",
                     content = {@Content(
@@ -188,14 +186,23 @@ public class IdentifierEndpoint extends AbstractEndpoint {
                             schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<?> find(@Valid @PathVariable("identifierId") Long identifierId,
-                                  @RequestHeader(HttpHeaders.ACCEPT) String accept) throws IdentifierNotFoundException,
+                                  @RequestHeader(HttpHeaders.ACCEPT) String accept,
+                                  Principal principal) throws IdentifierNotFoundException,
             DataServiceException, DataServiceConnectionException, MalformedException, FormatNotAvailableException,
-            QueryNotFoundException {
+            QueryNotFoundException, NotAllowedException {
         log.debug("endpoint find identifier, identifierId={}, accept={}", identifierId, accept);
         if (accept == null) {
             accept = "";
         }
         final Identifier identifier = identifierService.find(identifierId);
+        if (identifier.getStatus().equals(IdentifierStatusType.DRAFT)) {
+            if (principal == null) {
+                throw new NotAllowedException("Draft identifier: authentication required");
+            }
+            if (!identifier.getOwnedBy().equals(getId(principal))) {
+                throw new NotAllowedException("Draft identifier: not authorized");
+            }
+        }
         log.info("Found persistent identifier with id: {}", identifier.getId());
         switch (accept) {
             case "application/json":
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
index ade963c2559062b0ce225e0857ead02de351774c..51f323c30f1581314df88dab86ec2900775c215e 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
@@ -1,10 +1,7 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.auth.LoginRequestDto;
-import at.tuwien.api.auth.RefreshTokenRequestDto;
 import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.error.ApiErrorDto;
-import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
@@ -95,10 +92,11 @@ public class UserEndpoint extends AbstractEndpoint {
 
     @PostMapping
     @Transactional(rollbackFor = {Exception.class})
-    @PreAuthorize("!isAuthenticated()")
+    @PreAuthorize("hasAuthority('system')")
     @Observed(name = "dbrepo_user_create")
     @Operation(summary = "Create user",
-            description = "Creates a user in the auth service and metadata database. Requires that no credentials are sent in the request.")
+            description = "This webhook is called from the auth service to add a user to the metadata database. Requires role `system`.",
+            hidden = true)
     @ApiResponses(value = {
             @ApiResponse(responseCode = "201",
                     description = "Created user",
@@ -142,114 +140,10 @@ public class UserEndpoint extends AbstractEndpoint {
     public ResponseEntity<UserBriefDto> create(@NotNull @Valid @RequestBody CreateUserDto data)
             throws UserExistsException, EmailExistsException, AuthServiceException, AuthServiceConnectionException,
             UserNotFoundException, CredentialsInvalidException {
-        log.debug("endpoint create user, data.username={}", data.getUsername());
-        userService.validateUsernameNotExists(data.getUsername());
-        userService.validateEmailNotExists(data.getEmail());
+        log.debug("endpoint create user, data.id={}, data.username={}", data.getId(), data.getUsername());
         return ResponseEntity.status(HttpStatus.CREATED)
                 .body(userMapper.userToUserBriefDto(
-                        userService.create(data, authenticationService.create(data).getAttributes().getLdapId()[0])));
-    }
-
-    @PostMapping("/token")
-    @Observed(name = "dbrepo_user_token")
-    @Operation(summary = "Create token",
-            description = "Creates a user token via the Auth Service.")
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "202",
-                    description = "Obtained user token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = TokenDto.class))}),
-            @ApiResponse(responseCode = "400",
-                    description = "Invalid login request",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "403",
-                    description = "Not allowed to get token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "404",
-                    description = "Failed to find user in auth database",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "428",
-                    description = "Account is not fully setup in auth service (requires password change?)",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "502",
-                    description = "Connection to auth service failed",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "503",
-                    description = "Failed to get user in auth service",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-    })
-    public ResponseEntity<TokenDto> getToken(@NotNull @Valid @RequestBody LoginRequestDto data)
-            throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException,
-            AccountNotSetupException {
-        log.debug("endpoint get token, data.username={}", data.getUsername());
-        /* check */
-        try {
-            userService.findByUsername(data.getUsername());
-        } catch (UserNotFoundException e) {
-            /* need to sync */
-            log.warn("User with username {} does not exist in metadata database yet", data.getUsername());
-            final CreateUserDto request = CreateUserDto.builder()
-                    .username(data.getUsername())
-                    .email("noreply@example.com")
-                    .password(data.getPassword())
-                    .build();
-            final at.tuwien.api.keycloak.UserDto user = authenticationService.findByUsername(data.getUsername());
-            if (user.getAttributes().getLdapId() == null || user.getAttributes().getLdapId().length != 1) {
-                log.error("Failed to map ldap id for user with username: {}", data.getUsername());
-                throw new UserNotFoundException("Failed to map ldap id");
-            }
-            userService.create(request, user.getAttributes().getLdapId()[0]);
-            log.info("Patched missing user information for user with username: {}", data.getUsername());
-        }
-        return ResponseEntity.accepted()
-                .body(authenticationService.obtainToken(data));
-    }
-
-    @PutMapping("/token")
-    @Observed(name = "dbrepo_user_refresh_token")
-    @Operation(summary = "Refresh token",
-            description = "Refreshes user token by refresh token.")
-    @ApiResponses(value = {
-            @ApiResponse(responseCode = "202",
-                    description = "Refreshed user token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = TokenDto.class))}),
-            @ApiResponse(responseCode = "400",
-                    description = "Invalid refresh token",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "403",
-                    description = "Not allowed",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-            @ApiResponse(responseCode = "502",
-                    description = "Connection to auth service failed",
-                    content = {@Content(
-                            mediaType = "application/json",
-                            schema = @Schema(implementation = ApiErrorDto.class))}),
-    })
-    public ResponseEntity<TokenDto> refreshToken(@NotNull @Valid @RequestBody RefreshTokenRequestDto data)
-            throws AuthServiceConnectionException, CredentialsInvalidException {
-        log.debug("endpoint refresh token");
-        /* check */
-        return ResponseEntity.accepted()
-                .body(authenticationService.refreshToken(data.getRefreshToken()));
+                        userService.create(data)));
     }
 
     @GetMapping("/{userId}")
@@ -327,11 +221,16 @@ public class UserEndpoint extends AbstractEndpoint {
                     content = {@Content(
                             mediaType = "application/json",
                             schema = @Schema(implementation = ApiErrorDto.class))}),
+            @ApiResponse(responseCode = "503",
+                    description = "Failed to modify user at auth service",
+                    content = {@Content(
+                            mediaType = "application/json",
+                            schema = @Schema(implementation = ApiErrorDto.class))}),
     })
     public ResponseEntity<UserBriefDto> modify(@NotNull @PathVariable("userId") UUID userId,
-                                          @NotNull @Valid @RequestBody UserUpdateDto data,
-                                          @NotNull Principal principal) throws NotAllowedException,
-            UserNotFoundException, DatabaseNotFoundException {
+                                               @NotNull @Valid @RequestBody UserUpdateDto data,
+                                               @NotNull Principal principal) throws NotAllowedException,
+            UserNotFoundException, AuthServiceException {
         log.debug("endpoint modify a user, userId={}, data={}", userId, data);
         final User user = userService.findById(userId);
         if (!user.getId().equals(getId(principal))) {
@@ -381,9 +280,9 @@ public class UserEndpoint extends AbstractEndpoint {
     })
     public ResponseEntity<Void> password(@NotNull @PathVariable("userId") UUID userId,
                                          @NotNull @Valid @RequestBody UserPasswordDto data,
-                                         @NotNull Principal principal) throws NotAllowedException, AuthServiceException,
-            AuthServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, DataServiceException,
-            DataServiceConnectionException, CredentialsInvalidException {
+                                         @NotNull Principal principal) throws NotAllowedException,
+            UserNotFoundException, DatabaseNotFoundException, DataServiceException,
+            DataServiceConnectionException {
         log.debug("endpoint modify a user password, userId={}, principal.name={}", userId, principal.getName());
         final User user = userService.findById(userId);
         if (!user.getUsername().equals(principal.getName())) {
diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
index 3fc9c7216e5ad6f84fa530556708a8453eac2bac..a54f616b01e61edad50d85d4b5f0d494c9e429d6 100644
--- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
+++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java
@@ -2,8 +2,8 @@ package at.tuwien.validation;
 
 import at.tuwien.SortType;
 import at.tuwien.api.database.table.CreateTableDto;
-import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.identifier.IdentifierSaveDto;
 import at.tuwien.endpoints.AbstractEndpoint;
 import at.tuwien.entities.database.AccessType;
@@ -43,15 +43,6 @@ public class EndpointValidator extends AbstractEndpoint {
         this.accessService = accessService;
     }
 
-    public void validateOnlyPrivateDataAccess(Database database, Principal principal, boolean writeAccessOnly)
-            throws NotAllowedException, UserNotFoundException, AccessNotFoundException {
-        if (database.getIsPublic()) {
-            log.trace("database with id {} is public: no access needed", database.getId());
-            return;
-        }
-        validateOnlyAccess(database, principal, writeAccessOnly);
-    }
-
     public void validateOnlyPrivateSchemaAccess(Database database, Principal principal, boolean writeAccessOnly)
             throws NotAllowedException, UserNotFoundException, AccessNotFoundException {
         if (database.getIsSchemaPublic()) {
@@ -61,11 +52,6 @@ public class EndpointValidator extends AbstractEndpoint {
         validateOnlyAccess(database, principal, writeAccessOnly);
     }
 
-    public void validateOnlyPrivateDataAccess(Database database, Principal principal) throws NotAllowedException,
-            UserNotFoundException, AccessNotFoundException {
-        validateOnlyPrivateDataAccess(database, principal, false);
-    }
-
     public void validateOnlyPrivateSchemaAccess(Database database, Principal principal) throws NotAllowedException,
             UserNotFoundException, AccessNotFoundException {
         validateOnlyPrivateSchemaAccess(database, principal, false);
@@ -169,17 +155,6 @@ public class EndpointValidator extends AbstractEndpoint {
             log.error("Validation failed: column {} type serial demands non-null", optional4a.get().getName());
             throw new MalformedException("Validation failed: column " + optional4a.get().getName() + " type serial demands non-null");
         }
-        final Optional<CreateTableColumnDto> optional4b = data.getColumns()
-                .stream()
-                .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL) && data.getConstraints()
-                        .getUniques()
-                        .stream()
-                        .noneMatch(uk -> uk.size() == 1 && uk.contains(c.getName())))
-                .findFirst();
-        if (optional4b.isPresent()) {
-            log.error("Validation failed: column {} type serial demands a unique constraint", optional4b.get().getName());
-            throw new MalformedException("Validation failed: column " + optional4b.get().getName() + " type serial demands a unique constraint");
-        }
     }
 
     public boolean validateOnlyMineOrWriteAccessOrHasRole(User owner, Principal principal, DatabaseAccess access, String role) {
@@ -204,18 +179,6 @@ public class EndpointValidator extends AbstractEndpoint {
         return false;
     }
 
-    public boolean validateOnlyMineOrReadAccessOrHasRole(User owner, Principal principal, DatabaseAccess access, String role) {
-        if (validateOnlyMineOrWriteAccessOrHasRole(owner, principal, access, role)) {
-            return true;
-        }
-        if (access.getType().equals(AccessType.READ)) {
-            log.debug("validation passed: user {} has read access", principal.getName());
-            return true;
-        }
-        log.debug("validation failed: user {} has insufficient access {} or role", principal.getName(), access.getType());
-        return false;
-    }
-
     @Transactional(readOnly = true)
     public void validateOnlyOwnerOrWriteAll(Table table, User user) throws NotAllowedException,
             AccessNotFoundException {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c7316b3d15590979652ea4a04498271f068d2fc
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java
@@ -0,0 +1,42 @@
+package at.tuwien.converters;
+
+import at.tuwien.api.identifier.IdentifierStatusTypeDto;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Log4j2
+@SpringBootTest
+public class IdentifierStatusTypeDtoConverterUnitTest extends AbstractUnitTest {
+
+    @Autowired
+    private IdentifierStatusTypeDtoConverter identifierStatusTypeDtoConverter;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+    }
+
+    @Test
+    public void identifierStatusTypeDtoConverter_succeeds() {
+
+        /* test */
+        final IdentifierStatusTypeDto response = identifierStatusTypeDtoConverter.convert(IdentifierStatusTypeDto.DRAFT.getName());
+        assertEquals(IdentifierStatusTypeDto.DRAFT, response);
+    }
+
+    @Test
+    public void identifierStatusTypeDtoConverter_fails() {
+
+        /* test */
+        assertThrows(IllegalArgumentException.class, () -> {
+            identifierStatusTypeDtoConverter.convert("i_do_not_exist");
+        });
+    }
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java
similarity index 55%
rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java
rename to dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java
index 7215e5db918f226e6a826fce66e4e129ca4f0c5f..98abd668d8ec0e30a0f420682a0c7b7fd3e5704d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java
@@ -8,14 +8,15 @@ import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 @Log4j2
 @SpringBootTest
-public class IdentifierTypeConverterUnitTest extends AbstractUnitTest {
+public class IdentifierTypeDtoConverterUnitTest extends AbstractUnitTest {
 
     @Autowired
-    private IdentifierTypeConverter identifierTypeConverter;
+    private IdentifierTypeDtoConverter identifierTypeDtoConverter;
 
     @BeforeEach
     public void beforeEach() {
@@ -23,19 +24,19 @@ public class IdentifierTypeConverterUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void identifierTypeConverter_succeeds() {
+    public void IdentifierTypeDtoConverter_succeeds() {
 
         /* test */
-        final IdentifierTypeDto response = identifierTypeConverter.convert(IdentifierTypeDto.DATABASE.getName());
+        final IdentifierTypeDto response = identifierTypeDtoConverter.convert(IdentifierTypeDto.DATABASE.getName());
         assertEquals(IdentifierTypeDto.DATABASE, response);
     }
 
     @Test
-    public void identifierTypeConverter_fails() {
+    public void IdentifierTypeDtoConverter_fails() {
 
         /* test */
         assertThrows(IllegalArgumentException.class, () -> {
-            identifierTypeConverter.convert("i_do_not_exist");
+            identifierTypeDtoConverter.convert("i_do_not_exist");
         });
     }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfa4924957b9c300aeda92ad2ed305a4dd29b444
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java
@@ -0,0 +1,94 @@
+package at.tuwien.endpoints;
+
+import at.tuwien.api.database.AccessTypeDto;
+import at.tuwien.api.database.DatabaseAccessDto;
+import at.tuwien.api.user.UserDetailsDto;
+import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.DatabaseAccess;
+import at.tuwien.entities.user.User;
+import at.tuwien.exception.*;
+import at.tuwien.mapper.MetadataMapper;
+import at.tuwien.service.AccessService;
+import at.tuwien.service.DatabaseService;
+import at.tuwien.service.UserService;
+import at.tuwien.test.AbstractUnitTest;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.test.context.support.WithAnonymousUser;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.security.Principal;
+import java.util.List;
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@Log4j2
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+public class AbstractEndpointUnitTest extends AbstractUnitTest {
+
+    @Autowired
+    private AccessEndpoint accessEndpoint;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+    }
+
+    @Test
+    public void hasRole_noPrincipal_fails() {
+
+        /* test */
+        assertFalse(accessEndpoint.hasRole(null, "some-role"));
+    }
+
+    @Test
+    public void hasRole_noRole_fails() {
+
+        /* test */
+        assertFalse(accessEndpoint.hasRole(USER_1_PRINCIPAL, null));
+    }
+
+    @Test
+    public void getId_fails() {
+
+        /* test */
+        assertNull(accessEndpoint.getId(null));
+    }
+
+    @Test
+    public void getId_noId_fails() {
+        final Principal principal = new UsernamePasswordAuthenticationToken(UserDetailsDto.builder()
+                .id(null) // <<<
+                .build(), null);
+
+        /* test */
+        assertThrows(IllegalArgumentException.class, () -> {
+            accessEndpoint.getId(principal);
+        });
+    }
+
+    @Test
+    public void getId_incompatible_fails() {
+        final Principal principal = new UsernamePasswordAuthenticationToken("", null);
+
+        /* test */
+        assertThrows(IllegalArgumentException.class, () -> {
+            accessEndpoint.getId(principal);
+        });
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
index f4a700e859e68f5705475a63dbc66f2afeaeb5c4..376769e3c318eaabc93e2a65def2673d85d3e7d2 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java
@@ -219,6 +219,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         generic_update(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2, DATABASE_1_USER_2_WRITE_OWN_ACCESS);
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"})
+    public void update_ownerNoAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_update(USER_1_PRINCIPAL, USER_1, USER_1_ID, null, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"})
+    public void update_ownerNoWriteAllAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_update(USER_1_PRINCIPAL, USER_1, USER_LOCAL_ADMIN_ID, USER_LOCAL, null);
+        });
+    }
+
     @Test
     @WithAnonymousUser
     public void revoke_anonymous_fails() {
@@ -249,6 +269,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"})
+    public void revoke_ownerNoAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_revoke(USER_1_PRINCIPAL, USER_1, USER_1_ID, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"})
+    public void revoke_ownerNoWriteAllAccess_fails() {
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            generic_revoke(USER_1_PRINCIPAL, USER_1, USER_LOCAL_ADMIN_ID, USER_LOCAL);
+        });
+    }
+
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"})
     public void revoke_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException,
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
index 98ece39e1e78b5a2c2719974daf0a9443cd9c2ac..00185d9ea134c33eba73ba7c24a02ff2d606ab1d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java
@@ -1,12 +1,14 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.container.CreateContainerDto;
-import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.api.container.ContainerBriefDto;
 import at.tuwien.api.container.ContainerDto;
+import at.tuwien.api.container.CreateContainerDto;
 import at.tuwien.entities.container.Container;
-import at.tuwien.exception.*;
+import at.tuwien.exception.ContainerAlreadyExistsException;
+import at.tuwien.exception.ContainerNotFoundException;
+import at.tuwien.exception.ImageNotFoundException;
 import at.tuwien.service.impl.ContainerServiceImpl;
+import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -14,6 +16,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.test.context.support.WithAnonymousUser;
@@ -52,19 +55,23 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-container"})
-    public void findById_hasRole_succeeds() throws ContainerNotFoundException {
+    @WithMockUser(username = USER_1_USERNAME)
+    public void findById_succeeds() throws ContainerNotFoundException {
 
         /* test */
         findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL);
     }
 
     @Test
-    @WithMockUser(username = USER_4_USERNAME)
-    public void findById_noRole_succeeds() throws ContainerNotFoundException {
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME)
+    public void findById_system_succeeds() throws ContainerNotFoundException {
 
         /* test */
-        findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_4_PRINCIPAL);
+        final ResponseEntity<ContainerDto> response = findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_LOCAL_ADMIN_PRINCIPAL);
+        final HttpHeaders headers = response.getHeaders() ;
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_USERNAME), headers.get("X-Username"));
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_PASSWORD), headers.get("X-Password"));
+        assertEquals(List.of("X-Username X-Password"), headers.get("Access-Control-Expose-Headers"));
     }
 
     @Test
@@ -171,7 +178,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
-    public void findById_generic(Long containerId, Container container, Principal principal)
+    public ResponseEntity<ContainerDto> findById_generic(Long containerId, Container container, Principal principal)
             throws ContainerNotFoundException {
 
         /* mock */
@@ -182,6 +189,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest {
         final ResponseEntity<ContainerDto> response = containerEndpoint.findById(containerId, principal);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
+        return response;
     }
 
     public void delete_generic(Long containerId, Container container) throws ContainerNotFoundException {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
index 5118aec776b4f5956f8a82a23803f4ce2bfc6cdf..fd91fb5655ad563ee0b4f8503dbdb5b60db6fea9 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java
@@ -4,7 +4,6 @@ import at.tuwien.api.database.*;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
-import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.service.*;
 import at.tuwien.service.impl.DatabaseServiceImpl;
 import at.tuwien.test.AbstractUnitTest;
@@ -42,9 +41,6 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @MockBean
     private AccessService accessService;
 
-    @MockBean
-    private KeycloakGateway keycloakGateway;
-
     @MockBean
     private ContainerService containerService;
 
@@ -144,7 +140,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void refreshTableMetadata_anonymous_succeeds() {
+    public void refreshTableMetadata_anonymous_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -154,7 +150,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void refreshTableMetadata_noRole_succeeds() {
+    public void refreshTableMetadata_noRole_fails() {
 
         /* test */
         assertThrows(AccessDeniedException.class, () -> {
@@ -353,15 +349,12 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-visibility"})
     public void visibility_hasRole_succeeds() throws NotAllowedException, UserNotFoundException,
-            DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, AuthServiceException,
-            AuthServiceConnectionException {
+            DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException {
         final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder()
                 .isPublic(true)
                 .build();
 
         /* mock */
-        when(keycloakGateway.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
         when(userService.findById(USER_1_ID))
                 .thenReturn(USER_1);
 
@@ -509,7 +502,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-owner"})
     public void transfer_hasRole_succeeds() throws DataServiceConnectionException, DataServiceException,
             NotAllowedException, UserNotFoundException, DatabaseNotFoundException, SearchServiceException,
-            SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException {
+            SearchServiceConnectionException {
         final DatabaseTransferDto request = DatabaseTransferDto.builder()
                 .id(USER_4_ID)
                 .build();
@@ -517,8 +510,6 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
         /* mock */
         when(databaseService.findById(DATABASE_1_ID))
                 .thenReturn(DATABASE_1);
-        when(keycloakGateway.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
         when(userService.findById(USER_1_ID))
                 .thenReturn(USER_1);
         when(userService.findById(USER_4_ID))
@@ -550,7 +541,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_anonymous_fails() {
+    public void findById_anonymousPrivateSchemaNoAccess_fails() {
 
         /* test */
         assertThrows(NotAllowedException.class, () -> {
@@ -560,40 +551,51 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findById_anonymousNotFound_fails() {
+    public void findById_anonymousPublicSchemaNoAccess_succeeds() throws UserNotFoundException, NotAllowedException,
+            DataServiceException, DatabaseNotFoundException, ExchangeNotFoundException, DataServiceConnectionException {
 
         /* test */
-        assertThrows(DatabaseNotFoundException.class, () -> {
-            findById_generic(DATABASE_1_ID, null, null);
-        });
+        final DatabaseDto database = findById_generic(DATABASE_2_ID, DATABASE_2, null);
+        assertEquals(3, database.getTables().size());
+        assertEquals(1, database.getViews().size());
+        assertEquals(0, database.getAccesses().size());
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
-    public void findById_hasRole_succeeds() throws DataServiceException, DataServiceConnectionException,
-            DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException {
-
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
+    @WithAnonymousUser
+    public void findById_anonymousPrivateSchemaNoAccessSystem_succeeds() throws UserNotFoundException,
+            NotAllowedException, DataServiceException, DatabaseNotFoundException, ExchangeNotFoundException,
+            DataServiceConnectionException {
 
         /* test */
-        findById_generic(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL);
+        final DatabaseDto database = findById_generic(DATABASE_1_ID, DATABASE_1, USER_LOCAL_ADMIN_PRINCIPAL);
+        assertEquals(4, database.getTables().size());
+        assertEquals(2, database.getViews().size());
+        assertNotEquals(0, database.getAccesses().size());
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
-    public void findById_hasRoleForeign_succeeds() throws DataServiceException, DataServiceConnectionException,
-            DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException {
+    @WithAnonymousUser
+    public void findById_privateSchema_fails() {
 
-        /* pre-condition */
-        assertTrue(DATABASE_3_PUBLIC);
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            findById_generic(DATABASE_1_ID, DATABASE_1, null);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void findById_anonymousNotFound_fails() {
 
         /* test */
-        findById_generic(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL);
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            findById_generic(DATABASE_1_ID, null, null);
+        });
     }
 
     @Test
-    @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"})
+    @WithMockUser(username = USER_1_USERNAME)
     public void findById_ownerSeesAccessRights_succeeds() throws DataServiceException, DataServiceConnectionException,
             DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException {
 
@@ -602,10 +604,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(List.of(DATABASE_1_USER_1_WRITE_ALL_ACCESS, DATABASE_1_USER_2_READ_ACCESS));
 
         /* test */
-        final DatabaseDto response = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL);
-        final List<DatabaseAccessDto> accessList = response.getAccesses();
-        assertNotNull(accessList);
-        assertEquals(3, accessList.size());
+        final DatabaseDto database = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL);
+        assertEquals(4, database.getTables().size());
+        assertEquals(3, database.getViews().size());
+        assertEquals(3, database.getAccesses().size());
     }
 
     @Test
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
index 74a252c5a63572e569a1e7b8379637e2d34dc03d..419393b485096b84f6495bfcd6ce2910e0c9ae46 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java
@@ -122,12 +122,58 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         );
     }
 
+    public static Stream<Arguments> findAll_anonymousFilterDatabase_parameters() {
+        return Stream.of(
+                Arguments.arguments("dbid", DATABASE_1_ID, null, null, null, null, 1),
+                Arguments.arguments("qid", DATABASE_1_ID, QUERY_1_ID, null, null, null, 0),
+                Arguments.arguments("vid", DATABASE_1_ID, null, VIEW_1_ID, null, null, 0),
+                Arguments.arguments("tid", DATABASE_1_ID, null, null, TABLE_1_ID, null, 0),
+                Arguments.arguments("status_published", DATABASE_1_ID, null, null, null, "PUBLISHED", 1),
+                Arguments.arguments("status_draft", DATABASE_1_ID, null, null, null, "DRAFT", 0)
+        );
+    }
+
+    public static Stream<Arguments> findAll_filterSubset_parameters() {
+        return Stream.of(
+                Arguments.arguments("status_published", DATABASE_2_ID, null, null, null, "PUBLISHED", 0),
+                Arguments.arguments("status_draft", DATABASE_2_ID, null, null, null, "DRAFT", 1)
+        );
+    }
+
     public static Stream<Arguments> findAll_filterDatabase_parameters() {
         return Stream.of(
-                Arguments.arguments("dbid", DATABASE_1_ID, null, null, null, 4),
-                Arguments.arguments("qid", DATABASE_1_ID, QUERY_1_ID, null, null, 1),
-                Arguments.arguments("vid", DATABASE_1_ID, null, VIEW_1_ID, null, 1),
-                Arguments.arguments("tid", DATABASE_1_ID, null, null, TABLE_1_ID, 1)
+                Arguments.arguments("database_dbid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("database_qid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("database_tid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_dbid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_qid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_vid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("subset_tid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("view_dbid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("view_qid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("view_vid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, VIEW_1_ID, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("view_tid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("table_dbid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("table_qid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("table_vid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL),
+                Arguments.arguments("table_tid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 1, USER_1_PRINCIPAL),
+                Arguments.arguments("anon_database_dbid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_database_qid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null),
+                Arguments.arguments("anon_database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null),
+                Arguments.arguments("anon_database_tid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null),
+                Arguments.arguments("anon_subset_dbid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_subset_qid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, null),
+                Arguments.arguments("anon_subset_vid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null),
+                Arguments.arguments("anon_subset_tid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null),
+                Arguments.arguments("anon_view_dbid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_view_qid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null),
+                Arguments.arguments("anon_view_vid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, VIEW_1_ID, null, 1, null),
+                Arguments.arguments("anon_view_tid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null),
+                Arguments.arguments("anon_table_dbid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, null, 1, null),
+                Arguments.arguments("anon_table_qid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null),
+                Arguments.arguments("anon_table_vid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null),
+                Arguments.arguments("anon_table_tid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 1, null)
         );
     }
 
@@ -146,14 +192,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_empty_succeeds() throws FormatNotAvailableException {
+    public void findAll_empty_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of());
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/json", null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
@@ -161,12 +207,90 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         assertEquals(0, identifiers.size());
     }
 
+    @ParameterizedTest
+    @MethodSource("findAll_anonymousFilterDatabase_parameters")
+    @WithAnonymousUser
+    public void findAll_anonymousFilterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId,
+                                                         Long tableId, IdentifierStatusTypeDto status,
+                                                         Integer expectedSize) throws ViewNotFoundException,
+            TableNotFoundException, DatabaseNotFoundException {
+
+        /* mock */
+        when(identifierService.findAll())
+                .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7));
+        if (viewId != null) {
+            when(viewService.findById(DATABASE_1, VIEW_1_ID))
+                    .thenReturn(VIEW_1);
+        }
+        if (tableId != null) {
+            when(tableService.findById(DATABASE_1, TABLE_1_ID))
+                    .thenReturn(TABLE_1);
+        }
+
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, status, databaseId, queryId, viewId, tableId, "application/json", null);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(expectedSize, identifiers.size());
+    }
+
+    @ParameterizedTest
+    @MethodSource("findAll_filterSubset_parameters")
+    @WithMockUser(username = USER_2_USERNAME)
+    public void findAll_filterSubset_succeeds(String name, Long databaseId, Long queryId, Long viewId, Long tableId,
+                                              IdentifierStatusTypeDto status, Integer expectedSize) {
+
+        /* mock */
+        when(identifierService.findAll())
+                .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7));
+
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.SUBSET, status, databaseId, queryId, viewId, tableId, "application/json", USER_2_PRINCIPAL);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(expectedSize, identifiers.size());
+    }
+
+    @ParameterizedTest
+    @MethodSource("findAll_anonymousFilterDatabase_parameters")
+    @WithAnonymousUser
+    public void findAll_wrongPrincipalFilterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId,
+                                                              Long tableId, IdentifierStatusTypeDto status,
+                                                              Integer expectedSize)
+            throws ViewNotFoundException, TableNotFoundException, DatabaseNotFoundException {
+
+        /* mock */
+        when(identifierService.findAll())
+                .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7));
+        if (viewId != null) {
+            when(viewService.findById(DATABASE_1, VIEW_1_ID))
+                    .thenReturn(VIEW_1);
+        }
+        if (tableId != null) {
+            when(tableService.findById(DATABASE_1, TABLE_1_ID))
+                    .thenReturn(TABLE_1);
+        }
+
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, status, databaseId, queryId, viewId, tableId, "application/json", USER_2_PRINCIPAL);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(expectedSize, identifiers.size());
+    }
+
     @ParameterizedTest
     @MethodSource("findAll_filterDatabase_parameters")
     @WithAnonymousUser
-    public void findAll_filterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId, Long tableId,
-                                                Integer expectedSize) throws FormatNotAvailableException,
-            ViewNotFoundException, TableNotFoundException, DatabaseNotFoundException {
+    public void findAll_filterDatabase_succeeds(String name, IdentifierTypeDto type, IdentifierStatusTypeDto status,
+                                                Long databaseId, Long queryId, Long viewId, Long tableId,
+                                                Integer expectedSize, Principal principal) throws ViewNotFoundException,
+            TableNotFoundException, DatabaseNotFoundException {
 
         /* mock */
         when(identifierService.findAll())
@@ -181,7 +305,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         }
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(databaseId, queryId, viewId, tableId, "application/json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(type, status, databaseId, queryId, viewId, tableId, "application/json", principal);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
@@ -191,14 +315,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_json_succeeds() throws FormatNotAvailableException {
+    public void findAll_json_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of(IDENTIFIER_1));
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/json", null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
@@ -208,14 +332,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_jsonLd_succeeds() throws FormatNotAvailableException {
+    public void findAll_jsonLd_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of(IDENTIFIER_1));
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/ld+json");
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/ld+json", null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         final List<LdDatasetDto> identifiers = (List<LdDatasetDto>) response.getBody();
@@ -225,23 +349,95 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
-    public void findAll_format_fails() {
+    public void findAll_format_succeeds() {
 
         /* mock */
         when(identifierService.findAll())
                 .thenReturn(List.of(IDENTIFIER_1));
 
+        /* test */
+        final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "text/html", null);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody();
+        assertNotNull(identifiers);
+        assertEquals(1, identifiers.size());
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void find_textCsvDatabase_fails() throws IdentifierNotFoundException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_1_ID))
+                .thenReturn(IDENTIFIER_1);
+
         /* test */
         assertThrows(FormatNotAvailableException.class, () -> {
-            identifierEndpoint.findAll(null, null, null, null, "text/csv");
+            identifierEndpoint.find(IDENTIFIER_1_ID, "text/csv", null);
+        });
+    }
+
+    @Test
+    @WithAnonymousUser
+    public void find_draft_fails() throws IdentifierNotFoundException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_5_ID))
+                .thenReturn(IDENTIFIER_5);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_1_USERNAME)
+    public void find_draftNotOwner_fails() throws IdentifierNotFoundException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_5_ID))
+                .thenReturn(IDENTIFIER_5);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", USER_1_PRINCIPAL);
         });
     }
 
+    @Test
+    @WithMockUser(username = USER_2_USERNAME)
+    public void find_draft_succeeds() throws IdentifierNotFoundException, MalformedException, NotAllowedException,
+            DataServiceException, QueryNotFoundException, DataServiceConnectionException, FormatNotAvailableException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_5_ID))
+                .thenReturn(IDENTIFIER_5);
+
+        /* test */
+        identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", USER_2_PRINCIPAL);
+    }
+
     @Test
     @WithAnonymousUser
+    public void find_defaultHtmlRespondsJson_succeeds() throws IdentifierNotFoundException, MalformedException,
+            NotAllowedException, DataServiceException, QueryNotFoundException, DataServiceConnectionException,
+            FormatNotAvailableException {
+
+        /* mock */
+        when(identifierService.find(IDENTIFIER_1_ID))
+                .thenReturn(IDENTIFIER_1);
+
+        /* test */
+        identifierEndpoint.find(IDENTIFIER_1_ID, "text/html", null);
+    }
+
+    @Test
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_json0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "application/json";
         final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata0.json"), StandardCharsets.UTF_8), IdentifierDto.class);
 
@@ -250,7 +446,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final IdentifierDto body = (IdentifierDto) response.getBody();
         assertNotNull(body);
@@ -271,7 +467,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_json1_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "application/json";
         final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata1.json"), StandardCharsets.UTF_8), IdentifierDto.class);
 
@@ -280,7 +476,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final IdentifierDto body = (IdentifierDto) response.getBody();
         assertNotNull(body);
@@ -321,7 +517,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_csv_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/csv";
         final InputStreamResource compare = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv")));
         final InputStreamResource mock = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv")));
@@ -333,7 +529,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(mock);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_2_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_2_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final InputStreamResource body = (InputStreamResource) response.getBody();
         assertNotNull(body);
@@ -344,7 +540,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliography_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"),
                 StandardCharsets.UTF_8);
@@ -356,7 +552,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -365,9 +561,29 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithAnonymousUser
+    public void find_anonymousBibliographyApa0_fails() throws IOException, MalformedException,
+            IdentifierNotFoundException {
+        final String accept = "text/bibliography; style=apa";
+        final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"),
+                StandardCharsets.UTF_8);
+
+        /* mock */
+        when(identifierService.exportBibliography(IDENTIFIER_7, BibliographyTypeDto.APA))
+                .thenReturn(compare);
+        when(identifierService.find(IDENTIFIER_7_ID))
+                .thenReturn(IDENTIFIER_7);
+
+        /* test */
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_7_ID, accept, null);
+        });
+    }
+
+    @Test
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_bibliographyApa0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"),
                 StandardCharsets.UTF_8);
@@ -379,7 +595,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -390,7 +606,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyApa1_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"),
                 StandardCharsets.UTF_8);
@@ -402,7 +618,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -410,10 +626,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
-    public void find_bibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException,
+    @WithMockUser(username = USER_2_USERNAME)
+    public void find_draftBibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa2.txt"),
                 StandardCharsets.UTF_8);
@@ -425,7 +641,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_5);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -436,7 +652,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyApa3_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa3.txt"),
                 StandardCharsets.UTF_8);
@@ -448,7 +664,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_6);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_6_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_6_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -459,7 +675,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyApa4_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=apa";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa4.txt"),
                 StandardCharsets.UTF_8);
@@ -471,7 +687,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1_WITH_DOI);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -479,10 +695,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_bibliographyIeee0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee0.txt"),
                 StandardCharsets.UTF_8);
@@ -494,7 +710,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -505,7 +721,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyIeee1_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee1.txt"),
                 StandardCharsets.UTF_8);
@@ -517,7 +733,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -525,10 +741,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_2_USERNAME)
     public void find_bibliographyIeee2_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee2.txt"),
                 StandardCharsets.UTF_8);
@@ -540,7 +756,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_5);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -551,7 +767,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyIeee3_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=ieee";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee3.txt"),
                 StandardCharsets.UTF_8);
@@ -563,7 +779,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1_WITH_DOI);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -571,10 +787,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_4_USERNAME)
     public void find_bibliographyBibtex0_succeeds() throws IOException, MalformedException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex0.txt"),
                 StandardCharsets.UTF_8);
@@ -586,7 +802,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -597,7 +813,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyBibtex1_succeeds() throws MalformedException, IOException, DataServiceException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex1.txt"),
                 StandardCharsets.UTF_8);
@@ -609,7 +825,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -617,10 +833,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
+    @WithMockUser(username = USER_2_USERNAME)
     public void find_bibliographyBibtex2_succeeds() throws MalformedException, DataServiceException, IOException,
             DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex2.txt"),
                 StandardCharsets.UTF_8);
@@ -632,7 +848,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_5);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -643,7 +859,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_bibliographyBibtex3_succeeds() throws MalformedException, DataServiceException,
             DataServiceConnectionException, IOException, QueryNotFoundException, IdentifierNotFoundException,
-            FormatNotAvailableException {
+            FormatNotAvailableException, NotAllowedException {
         final String accept = "text/bibliography; style=bibtex";
         final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex3.txt"),
                 StandardCharsets.UTF_8);
@@ -655,7 +871,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1_WITH_DOI);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final String body = (String) response.getBody();
         assertNotNull(body);
@@ -665,7 +881,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void find_jsonLd_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException {
         final String accept = "application/ld+json";
 
         /* mock */
@@ -673,7 +889,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final LdDatasetDto body = (LdDatasetDto) response.getBody();
         assertNotNull(body);
@@ -689,22 +905,22 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_7);
 
         /* test */
-        assertThrows(FormatNotAvailableException.class, () -> {
-            identifierEndpoint.find(IDENTIFIER_7_ID, accept);
+        assertThrows(NotAllowedException.class, () -> {
+            identifierEndpoint.find(IDENTIFIER_7_ID, accept, null);
         });
     }
 
     @Test
     @WithAnonymousUser
     public void find_move_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+            QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException {
 
         /* mock */
         when(identifierService.find(IDENTIFIER_1_ID))
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, null);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, null, null);
         assertEquals(HttpStatus.MOVED_PERMANENTLY, response.getStatusCode());
     }
 
@@ -848,7 +1064,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void find_json_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException {
+            FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException, NotAllowedException {
         final String accept = "application/json";
 
         /* mock */
@@ -856,7 +1072,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
                 .thenReturn(IDENTIFIER_1);
 
         /* test */
-        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         final IdentifierDto body = (IdentifierDto) response.getBody();
         assertNotNull(body);
@@ -875,7 +1091,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @Test
     @WithAnonymousUser
     public void find_xml_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException,
-            IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException {
+            IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException,
+            NotAllowedException {
         final InputStreamResource resource = new InputStreamResource(FileUtils.openInputStream(
                 new File("src/test/resources/xml/datacite-example-dataset-v4.xml")));
 
@@ -892,7 +1109,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
     @WithAnonymousUser
     public void find_httpRedirect_succeeds() throws MalformedException, DataServiceException,
             DataServiceConnectionException, FormatNotAvailableException, QueryNotFoundException,
-            IdentifierNotFoundException {
+            IdentifierNotFoundException, NotAllowedException {
 
         /* test */
         final ResponseEntity<?> response = generic_find(null, null);
@@ -1291,7 +1508,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
 
     protected ResponseEntity<?> generic_find(String accept, InputStreamResource resource)
             throws MalformedException, DataServiceException, DataServiceConnectionException, FormatNotAvailableException,
-            QueryNotFoundException, IdentifierNotFoundException {
+            QueryNotFoundException, IdentifierNotFoundException, NotAllowedException {
 
         /* mock */
         when(identifierService.find(IDENTIFIER_1_ID))
@@ -1304,7 +1521,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest {
         }
 
         /* test */
-        return identifierEndpoint.find(IDENTIFIER_1_ID, accept);
+        return identifierEndpoint.find(IDENTIFIER_1_ID, accept, null);
     }
 
     protected static String inputStreamToString(InputStream inputStream) throws IOException {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java
index 152c17c4616a9637c08c50b9ba944dcef41c92f8..b1a65fc0cdce05ee9d1bcdfa0ad63e03f47933ba 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java
@@ -1,8 +1,6 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.auth.LoginRequestDto;
 import at.tuwien.api.auth.CreateUserDto;
-import at.tuwien.api.keycloak.UserAttributesDto;
 import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
@@ -17,9 +15,6 @@ import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -34,7 +29,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 import java.security.Principal;
 import java.util.List;
 import java.util.UUID;
-import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -56,13 +50,6 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     @Autowired
     private UserEndpoint userEndpoint;
 
-    public static Stream<Arguments> getToken_parameters() {
-        return Stream.of(
-                Arguments.arguments("null", null),
-                Arguments.arguments("empty", new UUID[]{})
-        );
-    }
-
     @BeforeEach
     public void beforeEach() {
         genesis();
@@ -104,31 +91,21 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    @WithAnonymousUser
-    public void create_anonymous_succeeds() throws UserExistsException, EmailExistsException, UserNotFoundException,
+    @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
+    public void create_succeeds() throws UserExistsException, EmailExistsException, UserNotFoundException,
             AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
-        final CreateUserDto request = CreateUserDto.builder()
-                .email(USER_1_EMAIL)
-                .username(USER_1_USERNAME)
-                .password(USER_1_PASSWORD)
-                .build();
 
         /* test */
-        create_generic(request, USER_1, USER_1_KEYCLOAK_DTO, USER_1_ID);
+        create_generic(USER_1_SIGNUP_REQUEST_DTO, USER_1);
     }
 
     @Test
     @WithMockUser(username = USER_1_USERNAME)
-    public void create_isAuthenticated_fails() {
-        final CreateUserDto request = CreateUserDto.builder()
-                .email(USER_2_EMAIL)
-                .username(USER_2_USERNAME)
-                .password(USER_2_PASSWORD)
-                .build();
+    public void create_noRole_fails() {
 
         /* test */
         assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
-            create_generic(request, null, null, null);
+            create_generic(USER_1_SIGNUP_REQUEST_DTO, null);
         });
     }
 
@@ -235,7 +212,8 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
 
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-user-information"})
-    public void modify_succeeds() throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException {
+    public void modify_succeeds() throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException,
+            AuthServiceException, AuthServiceConnectionException {
         final UserUpdateDto request = UserUpdateDto.builder()
                 .firstname(USER_1_FIRSTNAME)
                 .lastname(USER_1_LASTNAME)
@@ -286,136 +264,6 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
         password_generic(USER_1_PRINCIPAL, request);
     }
 
-    @Test
-    @WithAnonymousUser
-    public void getToken_anonymous_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException {
-
-        /* test */
-        getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, USER_1);
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void getToken_loggedIn_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException {
-
-        /* test */
-        getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, USER_1);
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void getToken_notExists_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException {
-
-        /* mock */
-        when(authenticationService.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
-        when(userService.create(any(CreateUserDto.class), any(UUID.class)))
-                .thenReturn(USER_1);
-
-        /* test */
-        getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null);
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void getToken_notExists_fails() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        doThrow(UserNotFoundException.class)
-                .when(authenticationService)
-                .findByUsername(USER_1_USERNAME);
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null);
-        });
-    }
-
-    @ParameterizedTest
-    @MethodSource("getToken_parameters")
-    @WithAnonymousUser
-    public void getToken_missingLdapId_fails(String name, UUID[] ldapId) throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException {
-        final at.tuwien.api.keycloak.UserDto mock = at.tuwien.api.keycloak.UserDto.builder()
-                .attributes(UserAttributesDto.builder()
-                        .ldapId(ldapId)
-                        .build())
-                .build();
-
-        /* mock */
-        when(authenticationService.findByUsername(USER_1_USERNAME))
-                .thenReturn(mock);
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null);
-        });
-    }
-
-    @Test
-    @WithAnonymousUser
-    public void refreshToken_anonymous_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        when(authenticationService.refreshToken(anyString()))
-                .thenReturn(TOKEN_DTO);
-
-        /* test */
-        final ResponseEntity<?> response = userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void refreshToken_loggedIn_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        when(authenticationService.refreshToken(anyString()))
-                .thenReturn(TOKEN_DTO);
-
-        /* test */
-        final ResponseEntity<?> response = userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void refreshToken_authServiceConnection_fails() throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-
-        /* mock */
-        doThrow(AuthServiceConnectionException.class)
-                .when(authenticationService)
-                .refreshToken(anyString());
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        });
-    }
-
-    @Test
-    @WithMockUser(username = USER_1_USERNAME)
-    public void refreshToken_invalidCredentials_fails() throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-
-        /* mock */
-        doThrow(CredentialsInvalidException.class)
-                .when(authenticationService)
-                .refreshToken(anyString());
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO);
-        });
-    }
-
     /* ################################################################################################### */
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
@@ -445,17 +293,12 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
         return response.getBody();
     }
 
-    protected void create_generic(CreateUserDto data, User user, at.tuwien.api.keycloak.UserDto userDto, UUID id)
-            throws UserExistsException, EmailExistsException, UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException {
+    protected void create_generic(CreateUserDto data, User user) throws UserExistsException, EmailExistsException,
+            UserNotFoundException, AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
 
         /* mock */
-        when(userService.create(eq(data), any(UUID.class)))
+        when(userService.create(any(CreateUserDto.class)))
                 .thenReturn(user);
-        when(authenticationService.findByUsername(data.getUsername()))
-                .thenReturn(userDto);
-        when(authenticationService.create(data))
-                .thenReturn(userDto);
 
         /* test */
         final ResponseEntity<UserBriefDto> response = userEndpoint.create(data);
@@ -486,7 +329,8 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
     }
 
     protected void modify_generic(UUID userId, User user, Principal principal, UserUpdateDto data)
-            throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException {
+            throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException, AuthServiceException,
+            AuthServiceConnectionException {
         /* mock */
         if (user != null) {
             when(userService.findById(userId))
@@ -522,26 +366,4 @@ public class UserEndpointUnitTest extends AbstractUnitTest {
         final ResponseEntity<?> response = userEndpoint.password(USER_1_ID, data, principal);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
-
-    protected void getToken_generic(LoginRequestDto request, Principal principal, User user)
-            throws UserNotFoundException, AuthServiceConnectionException, AccountNotSetupException,
-            CredentialsInvalidException, AuthServiceException {
-
-        /* mock */
-        when(authenticationService.obtainToken(any(LoginRequestDto.class)))
-                .thenReturn(TOKEN_DTO);
-        if (user != null) {
-            when(userService.findByUsername(principal.getName()))
-                    .thenReturn(user);
-        } else {
-            doThrow(UserNotFoundException.class)
-                    .when(userService)
-                    .findByUsername(principal.getName());
-        }
-
-        /* test */
-        final ResponseEntity<?> response = userEndpoint.getToken(request);
-        assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
-        assertNotNull(response.getBody());
-    }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
index 4f1a3da45c87922aabd73ee6e75b1cca3160dd62..d1434ef9e4035cd13d81a4f12ec68bad71683bf1 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java
@@ -1,7 +1,7 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.database.ViewBriefDto;
 import at.tuwien.api.database.CreateViewDto;
+import at.tuwien.api.database.ViewBriefDto;
 import at.tuwien.api.database.ViewDto;
 import at.tuwien.api.database.ViewUpdateDto;
 import at.tuwien.entities.database.Database;
@@ -21,6 +21,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.AccessDeniedException;
@@ -173,6 +174,25 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS);
     }
 
+    @Test
+    @WithMockUser(username = USER_2_USERNAME)
+    public void find_publicSystem_succeeds() throws UserNotFoundException, DatabaseNotFoundException,
+            AccessNotFoundException, ViewNotFoundException {
+
+        /* test */
+        final ResponseEntity<ViewDto> response = find_generic(DATABASE_3_ID, DATABASE_3, USER_LOCAL_ADMIN_PRINCIPAL,
+                USER_LOCAL_ADMIN_ID, null, null);
+        final HttpHeaders headers = response.getHeaders();
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_USERNAME), headers.get("X-Username"));
+        assertEquals(List.of(CONTAINER_1_PRIVILEGED_PASSWORD), headers.get("X-Password"));
+        assertEquals(List.of(CONTAINER_1_HOST), headers.get("X-Host"));
+        assertEquals(List.of("" + CONTAINER_1_PORT), headers.get("X-Port"));
+        assertEquals(List.of(IMAGE_1_JDBC), headers.get("X-Type"));
+        assertEquals(List.of(DATABASE_3_INTERNALNAME), headers.get("X-Database"));
+        assertEquals(List.of(VIEW_5_INTERNAL_NAME), headers.get("X-View"));
+        assertEquals(List.of("X-Username X-Password X-Host X-Port X-Type X-Database X-View"), headers.get("Access-Control-Expose-Headers"));
+    }
+
     @Test
     @WithMockUser(username = USER_2_USERNAME)
     public void find_publicHasRoleHasAccess_succeeds() throws UserNotFoundException, DatabaseNotFoundException,
@@ -494,9 +514,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
         assertEquals(VIEW_1_NAME, response.getBody().getName());
     }
 
-    protected void find_generic(Long databaseId, Database database, Principal principal, UUID userId, User user,
-                                DatabaseAccess access) throws DatabaseNotFoundException, UserNotFoundException,
-            AccessNotFoundException, ViewNotFoundException {
+    protected ResponseEntity<ViewDto> find_generic(Long databaseId, Database database, Principal principal,
+                                                   UUID userId, User user, DatabaseAccess access)
+            throws DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, ViewNotFoundException {
 
         /* mock */
         when(databaseService.findById(databaseId))
@@ -514,18 +534,18 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
             when(userService.findById(userId))
                     .thenReturn(user);
             when(viewService.findById(any(Database.class), anyLong()))
-                    .thenReturn(VIEW_1);
+                    .thenReturn(VIEW_5);
         } else {
             when(viewService.findById(any(Database.class), anyLong()))
-                    .thenReturn(VIEW_1);
+                    .thenReturn(VIEW_5);
         }
 
         /* test */
-        final ResponseEntity<ViewDto> response = viewEndpoint.find(databaseId, VIEW_1_ID, USER_1_PRINCIPAL);
+        final ResponseEntity<ViewDto> response = viewEndpoint.find(databaseId, VIEW_5_ID, principal);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
-        assertEquals(VIEW_1_ID, response.getBody().getId());
-        assertEquals(VIEW_1_NAME, response.getBody().getName());
+        assertEquals(VIEW_5_ID, response.getBody().getId());
+        return response;
     }
 
     protected void delete_generic(Long databaseId, Database database, Long viewId, View view, Principal principal,
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e72cd7fa7591a7e641c74df6eab07845b0a193ea
--- /dev/null
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java
@@ -0,0 +1,114 @@
+package at.tuwien.gateway;
+
+import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.gateway.impl.KeycloakGatewayImpl;
+import at.tuwien.test.AbstractUnitTest;
+import at.tuwien.utils.KeycloakUtils;
+import dasniko.testcontainers.keycloak.KeycloakContainer;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.images.PullPolicy;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Log4j2
+@SpringBootTest
+@Testcontainers
+@ExtendWith(SpringExtension.class)
+public class KeycloakGatewayIntegrationTest extends AbstractUnitTest {
+
+    @Autowired
+    private KeycloakGatewayImpl keycloakGateway;
+
+    @Autowired
+    private KeycloakUtils keycloakUtils;
+
+    @BeforeEach
+    public void beforeEach() {
+        genesis();
+        /* auth service */
+        keycloakUtils.deleteUser(USER_1_USERNAME);
+    }
+
+    @Container
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE)
+            .withImagePullPolicy(PullPolicy.alwaysPull())
+            .withAdminUsername("admin")
+            .withAdminPassword("admin")
+            .withRealmImportFile("./init/dbrepo-realm.json")
+            .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false");
+
+    @DynamicPropertySource
+    static void keycloakProperties(DynamicPropertyRegistry registry) {
+        final String authServiceEndpoint = "http://localhost:" + keycloakContainer.getMappedPort(8080);
+        log.trace("set auth endpoint: {}", authServiceEndpoint);
+        registry.add("dbrepo.endpoints.authService", () -> authServiceEndpoint);
+    }
+
+    @Test
+    public void deleteUser_succeeds() throws UserNotFoundException {
+
+        /* mock */
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        keycloakGateway.deleteUser(keycloakUtils.getUserId(USER_1_USERNAME));
+    }
+
+    @Test
+    public void deleteUser_notFound_fails() {
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            keycloakGateway.deleteUser(USER_1_ID);
+        });
+    }
+
+    @Test
+    public void findByUsername_succeeds() throws UserNotFoundException {
+
+        /* mock */
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        keycloakGateway.findByUsername(USER_1_USERNAME);
+    }
+
+    @Test
+    public void findByUsername_notFound_fails() {
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            keycloakGateway.findByUsername(USER_1_USERNAME);
+        });
+    }
+
+    @Test
+    public void updateUserCredentials_succeeds() throws UserNotFoundException {
+
+        /* mock */
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
+
+        /* test */
+        keycloakGateway.updateUserCredentials(keycloakUtils.getUserId(USER_1_USERNAME), USER_1_PASSWORD_DTO);
+    }
+
+    @Test
+    public void updateUserCredentials_notFound_fails() {
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            keycloakGateway.updateUserCredentials(keycloakUtils.getUserId(USER_1_USERNAME), USER_1_PASSWORD_DTO);
+        });
+    }
+
+}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java
deleted file mode 100644
index bb3bcbb094ad1e9a2510abe20b9649ee73e6e975..0000000000000000000000000000000000000000
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java
+++ /dev/null
@@ -1,489 +0,0 @@
-package at.tuwien.gateway;
-
-import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserDto;
-import at.tuwien.exception.*;
-import at.tuwien.gateway.impl.KeycloakGatewayImpl;
-import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.http.*;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestTemplate;
-
-import java.nio.charset.Charset;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
-
-@Log4j2
-@SpringBootTest
-@ExtendWith(SpringExtension.class)
-public class KeycloakGatewayUnitTest extends AbstractUnitTest {
-
-    @MockBean
-    @Qualifier("keycloakRestTemplate")
-    private RestTemplate keycloakRestTemplate;
-
-    @MockBean
-    @Qualifier("restTemplate")
-    private RestTemplate restTemplate;
-
-    @Autowired
-    private KeycloakGatewayImpl keycloakGateway;
-
-    @Test
-    public void createUser_succeeds() throws UserExistsException, EmailExistsException, AuthServiceException,
-            AuthServiceConnectionException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.CREATED)
-                        .build());
-
-        /* test */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-    }
-
-    @Test
-    public void createUser_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        });
-    }
-
-    @Test
-    public void createUser_sameUsername_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(UserExistsException.class, () -> {
-            keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        });
-    }
-
-    @Test
-    public void createUser_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        });
-    }
-
-    @Test
-    public void deleteUser_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .build());
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void deleteUser_succeeds() throws UserNotFoundException, AuthServiceException,
-            AuthServiceConnectionException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        keycloakGateway.deleteUser(USER_1_ID);
-    }
-
-    @Test
-    public void deleteUser_notFound_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.NotFound.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void deleteUser_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void deleteUser_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.deleteUser(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void updateUserCredentials_succeeds() throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT)
-                        .build());
-
-        /* test */
-        keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-    }
-
-    @Test
-    public void updateUserCredentials_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .build());
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-        });
-    }
-
-    @Test
-    public void updateUserCredentials_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-        });
-    }
-
-    @Test
-    public void updateUserCredentials_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO);
-        });
-    }
-
-    @Test
-    public void findByUsername_notFound_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(new UserDto[]{}));
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            keycloakGateway.findByUsername(USER_1_USERNAME);
-        });
-    }
-
-    @Test
-    public void findByUsername_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.findByUsername(USER_1_USERNAME);
-        });
-    }
-
-    @Test
-    public void findByUsername_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.findByUsername(USER_1_USERNAME);
-        });
-    }
-
-    @Test
-    public void findById_succeeds() throws UserNotFoundException, AuthServiceException, AuthServiceConnectionException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(USER_1_KEYCLOAK_DTO));
-
-        /* test */
-        final UserDto response = keycloakGateway.findById(USER_1_ID);
-        assertEquals(USER_1_ID, response.getId());
-    }
-
-    @Test
-    public void findById_notFound_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.NotFound.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
-
-        /* test */
-        assertThrows(UserNotFoundException.class, () -> {
-            keycloakGateway.findById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void findById_connection_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpServerErrorException.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.findById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void findById_unexpected_fails() {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-        doThrow(HttpClientErrorException.Conflict.class)
-                .when(keycloakRestTemplate)
-                .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class));
-
-        /* test */
-        assertThrows(AuthServiceException.class, () -> {
-            keycloakGateway.findById(USER_1_ID);
-        });
-    }
-
-    @Test
-    public void refreshUserToken_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-
-        /* test */
-        final TokenDto response = keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        assertNotNull(response.getAccessToken());
-    }
-
-    @Test
-    public void refreshUserToken_connection_fails() {
-
-        /* mock */
-        doThrow(HttpServerErrorException.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void refreshUserToken_unauthorized_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.Unauthorized.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void refreshUserToken_badRequest_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.BadRequest.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void refreshUserToken_badRequestInactiveSession_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.BadRequest.create(HttpStatus.BAD_REQUEST, "Session not active", new HttpHeaders(), new byte[]{}, Charset.defaultCharset()))
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken());
-        });
-    }
-
-    @Test
-    public void obtainUserToken_succeeds() throws AuthServiceConnectionException,
-            AccountNotSetupException, CredentialsInvalidException {
-
-        /* mock */
-        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)))
-                .thenReturn(ResponseEntity.status(HttpStatus.OK)
-                        .body(TOKEN_DTO));
-
-        /* test */
-        final TokenDto response = keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        assertNotNull(response.getAccessToken());
-    }
-
-    @Test
-    public void obtainUserToken_connection_fails() {
-
-        /* mock */
-        doThrow(HttpServerErrorException.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(AuthServiceConnectionException.class, () -> {
-            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        });
-    }
-
-    @Test
-    public void obtainUserToken_unauthorized_fails() {
-
-        /* mock */
-        doThrow(HttpClientErrorException.Unauthorized.class)
-                .when(restTemplate)
-                .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class));
-
-        /* test */
-        assertThrows(CredentialsInvalidException.class, () -> {
-            keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD);
-        });
-    }
-
-}
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java
index fa0b6f64f76712b82ce1386ad38ff621d5e561dc..0365db6c4a09dfaedb742528b3bb08d4784d53f1 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java
@@ -9,7 +9,6 @@ import at.tuwien.repository.ContainerRepository;
 import at.tuwien.repository.DatabaseRepository;
 import at.tuwien.repository.LicenseRepository;
 import at.tuwien.repository.UserRepository;
-import at.tuwien.service.AuthenticationService;
 import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.utils.KeycloakUtils;
 import dasniko.testcontainers.keycloak.KeycloakContainer;
@@ -49,9 +48,6 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     @Autowired
     private KeycloakUtils keycloakUtils;
 
-    @Autowired
-    private KeycloakGateway keycloakGateway;
-
     @Autowired
     private UserRepository userRepository;
 
@@ -65,7 +61,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     private DatabaseRepository databaseRepository;
 
     @Autowired
-    private AuthenticationService authenticationService;
+    private KeycloakGateway keycloakGateway;
 
     @Container
     private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE)
@@ -97,7 +93,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_database_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
@@ -112,7 +108,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_database_basicAdmin_succeeds() throws Exception {
 
         /* pre condition */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD)))
@@ -127,8 +123,8 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_database_bearerAdmin_succeeds() throws Exception {
 
         /* pre condition */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
-        final TokenDto jwt = authenticationService.obtainToken(USER_LOCAL_ADMIN_LOGIN_REQUEST_DTO);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        final TokenDto jwt = keycloakGateway.obtainUserToken(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1").header("Authorization", "Bearer " + jwt.getAccessToken()))
@@ -143,8 +139,8 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_table_bearerAdmin_succeeds() throws Exception {
 
         /* pre condition */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
-        final TokenDto jwt = authenticationService.obtainToken(USER_LOCAL_ADMIN_LOGIN_REQUEST_DTO);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        final TokenDto jwt = keycloakGateway.obtainUserToken(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD);
 
 
         /* test */
@@ -160,7 +156,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_table_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
@@ -175,7 +171,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_table_basicAdmin_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD)))
@@ -190,7 +186,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_view_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/database/1/view/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
@@ -205,7 +201,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest
     public void findById_container_basicUser_succeeds() throws Exception {
 
         /* mock */
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
 
         /* test */
         this.mockMvc.perform(get("/api/container/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD)))
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
index dc41121b90133b3c759ad556a71c081d0ed9aeae..790262c7399d36fb0d9a3cf6103f7899300daffb 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
@@ -1,12 +1,14 @@
 package at.tuwien.mvc;
 
-import at.tuwien.api.auth.RefreshTokenRequestDto;
 import at.tuwien.api.container.CreateContainerDto;
-import at.tuwien.test.AbstractUnitTest;
-import at.tuwien.api.database.*;
+import at.tuwien.api.database.DatabaseModifyImageDto;
+import at.tuwien.api.database.DatabaseModifyVisibilityDto;
+import at.tuwien.api.database.DatabaseTransferDto;
 import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto;
+import at.tuwien.api.identifier.IdentifierTypeDto;
 import at.tuwien.config.MetricsConfig;
 import at.tuwien.endpoints.*;
+import at.tuwien.test.AbstractUnitTest;
 import io.micrometer.observation.annotation.Observed;
 import io.micrometer.observation.tck.TestObservationRegistry;
 import io.swagger.v3.oas.annotations.Operation;
@@ -24,7 +26,6 @@ import org.springframework.boot.test.context.TestConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Import;
 import org.springframework.http.MediaType;
-import org.springframework.security.test.context.support.WithAnonymousUser;
 import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.test.web.servlet.MockMvc;
@@ -32,7 +33,10 @@ import org.springframework.test.web.servlet.MockMvc;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -273,7 +277,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
             /* ignore */
         }
         try {
-            identifierEndpoint.findAll(DATABASE_1_ID, null, null, null, MediaType.APPLICATION_JSON_VALUE);
+            identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, MediaType.APPLICATION_JSON_VALUE, null);
         } catch (Exception e) {
             /* ignore */
         }
@@ -587,45 +591,16 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest {
         } catch (Exception e) {
             /* ignore */
         }
-        try {
-            userEndpoint.refreshToken(RefreshTokenRequestDto.builder().build());
-        } catch (Exception e) {
-            /* ignore */
-        }
 
         /* test */
-        for (String metric : List.of("dbrepo_user_refresh_token", "dbrepo_users_list",
-                "dbrepo_user_find", "dbrepo_user_modify", "dbrepo_user_password_modify")) {
+        for (String metric : List.of("dbrepo_users_list", "dbrepo_user_find", "dbrepo_user_modify",
+                "dbrepo_user_password_modify")) {
             assertThat(registry)
                     .hasObservationWithNameEqualTo(metric);
         }
         generic_openApiDocs(UserEndpoint.class);
     }
 
-    @Test
-    @WithAnonymousUser
-    public void prometheusUserEndpoint2_succeeds() {
-
-        /* mock */
-        try {
-            userEndpoint.create(USER_1_SIGNUP_REQUEST_DTO);
-        } catch (Exception e) {
-            /* ignore */
-        }
-        try {
-            userEndpoint.getToken(USER_1_LOGIN_REQUEST_DTO);
-        } catch (Exception e) {
-            /* ignore */
-        }
-
-        /* test */
-        for (String metric : List.of("dbrepo_user_create", "dbrepo_user_token")) {
-            assertThat(registry)
-                    .hasObservationWithNameEqualTo(metric);
-        }
-        // already done above
-    }
-
     @Test
     @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-view", "delete-database-view"})
     public void prometheusViewEndpoint_succeeds() {
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
index fa1cd5d4beeb1fe8fb40d8f59fa974b5d2501dba..d655a25cf1f599b2e92a9fd426cfa343747a3fe1 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java
@@ -1,9 +1,10 @@
 package at.tuwien.service;
 
-import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.test.AbstractUnitTest;
+import at.tuwien.utils.KeycloakUtils;
 import dasniko.testcontainers.keycloak.KeycloakContainer;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
@@ -19,6 +20,8 @@ import org.testcontainers.images.PullPolicy;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import java.util.UUID;
+
 @Log4j2
 @Testcontainers
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@@ -32,13 +35,16 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
     @Autowired
     private KeycloakGateway keycloakGateway;
 
+    @Autowired
+    private KeycloakUtils keycloakUtils;
+
     @BeforeEach
     public void beforeEach() {
         genesis();
     }
 
     @Container
-    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0")
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE)
             .withImagePullPolicy(PullPolicy.alwaysPull())
             .withAdminUsername("admin")
             .withAdminPassword("admin")
@@ -47,7 +53,9 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
 
     @DynamicPropertySource
     static void keycloakProperties(DynamicPropertyRegistry registry) {
-        registry.add("dbrepo.endpoints.authService", () -> "http://localhost:" + keycloakContainer.getMappedPort(8080));
+        final String authServiceEndpoint = "http://localhost:" + keycloakContainer.getMappedPort(8080);
+        log.trace("set auth endpoint: {}", authServiceEndpoint);
+        registry.add("dbrepo.endpoints.authService", () -> authServiceEndpoint);
     }
 
     @Test
@@ -55,14 +63,10 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
             AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException {
 
         /* mock */
-        try {
-            keycloakGateway.deleteUser(keycloakGateway.findByUsername(USER_1_USERNAME).getId());
-        } catch (Exception e) {
-            /* ignore */
-        }
-        keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
+        keycloakUtils.deleteUser(USER_1_USERNAME);
+        keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST);
         final User request = User.builder()
-                .id(keycloakGateway.findByUsername(USER_1_USERNAME).getId())
+                .keycloakId(UUID.fromString(keycloakGateway.findByUsername(USER_1_USERNAME).getId()))
                 .username(USER_1_USERNAME)
                 .build();
 
@@ -70,20 +74,4 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest {
         authenticationService.delete(request);
     }
 
-    @Test
-    public void create_succeeds() throws EmailExistsException, UserExistsException,
-            DataServiceConnectionException, AuthServiceException, AuthServiceConnectionException,
-            CredentialsInvalidException {
-
-        /* mock */
-        try {
-            keycloakGateway.deleteUser(keycloakGateway.findByUsername(USER_1_USERNAME).getId());
-        } catch (Exception e) {
-            /* ignore */
-        }
-
-        /* test */
-        authenticationService.create(USER_1_SIGNUP_REQUEST_DTO);
-    }
-
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java
index 8724e08be1c3312b74f487f413d035b7bfa1dfd2..e9d6b158ce097fc469694ee1d09e068357120d39 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java
@@ -1,12 +1,10 @@
 package at.tuwien.service;
 
-import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.EmailExistsException;
-import at.tuwien.exception.UserExistsException;
-import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.exception.*;
+import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.repository.UserRepository;
 import at.tuwien.test.AbstractUnitTest;
 import lombok.extern.log4j.Log4j2;
@@ -15,12 +13,14 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.doNothing;
 
 @Log4j2
 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@@ -34,6 +34,9 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
     @Autowired
     private UserService userService;
 
+    @MockBean
+    private KeycloakGateway keycloakGateway;
+
     @BeforeEach
     public void beforeEach() {
         genesis();
@@ -68,20 +71,16 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void create_succeeds() throws UserExistsException, UserNotFoundException, EmailExistsException {
-        final CreateUserDto request = CreateUserDto.builder()
-                .username(USER_2_USERNAME)
-                .password(USER_2_PASSWORD)
-                .email(USER_2_EMAIL)
-                .build();
+    public void create_succeeds() throws UserExistsException, UserNotFoundException, EmailExistsException,
+            AuthServiceException, AuthServiceConnectionException {
 
         /* test */
-        final User response = userService.create(request, USER_2_ID);
+        final User response = userService.create(USER_2_SIGNUP_REQUEST_DTO);
         assertEquals(USER_2_USERNAME, response.getUsername());
     }
 
     @Test
-    public void modify_succeeds() {
+    public void modify_succeeds() throws UserNotFoundException, AuthServiceException {
         final UserUpdateDto request = UserUpdateDto.builder()
                 .firstname(USER_1_FIRSTNAME)
                 .lastname(USER_1_LASTNAME)
@@ -91,6 +90,11 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
                 .language("de")
                 .build();
 
+        /* mock */
+        doNothing()
+                .when(keycloakGateway)
+                .updateUser(USER_1_ID, request);
+
         /* test */
         final User response = userService.modify(USER_1, request);
         assertEquals(USER_1_ID, response.getId());
@@ -103,17 +107,14 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePassword_succeeds() {
+    public void updatePassword_succeeds() throws UserNotFoundException, AuthServiceException,
+            AuthServiceConnectionException {
         final UserPasswordDto request = UserPasswordDto.builder()
                 .password(USER_3_PASSWORD)
                 .build();
 
         /* mock */
-        final User user = userService.create(CreateUserDto.builder()
-                .username(USER_3_USERNAME)
-                .password(USER_3_PASSWORD)
-                .email(USER_3_EMAIL)
-                .build(), USER_3_ID);
+        final User user = userService.create(USER_3_SIGNUP_REQUEST_DTO);
 
         /* test */
         userService.updatePassword(user, request);
@@ -151,20 +152,4 @@ public class UserServicePersistenceTest extends AbstractUnitTest {
             userService.validateUsernameNotExists(USER_1_USERNAME);
         });
     }
-
-    @Test
-    public void validateEmailNotExists_succeeds() throws EmailExistsException {
-
-        /* test */
-        userService.validateEmailNotExists(USER_2_EMAIL);
-    }
-
-    @Test
-    public void validateEmailNotExists_fails() {
-
-        /* test */
-        assertThrows(EmailExistsException.class, () -> {
-            userService.validateEmailNotExists(USER_1_EMAIL);
-        });
-    }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
index a9fe4694cc69d8eb347e9fefd12498704b8797fd..4c423aa25b6fd36f82485d836c190c1b2779e12d 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java
@@ -1,10 +1,10 @@
 package at.tuwien.service;
 
-import at.tuwien.test.AbstractUnitTest;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.repository.UserRepository;
+import at.tuwien.test.AbstractUnitTest;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -86,20 +86,15 @@ public class UserServiceUnitTest extends AbstractUnitTest {
                 .thenReturn(Optional.of(USER_1));
         when(userRepository.save(any(User.class)))
                 .thenReturn(USER_1);
-        doNothing()
-                .when(keycloakGateway)
-                .createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST);
-        when(keycloakGateway.findByUsername(USER_1_USERNAME))
-                .thenReturn(USER_1_KEYCLOAK_DTO);
 
         /* test */
-        final User response = userService.create(USER_1_SIGNUP_REQUEST_DTO, USER_1_ID);
+        final User response = userService.create(USER_1_SIGNUP_REQUEST_DTO);
         assertEquals(USER_1_ID, response.getId());
         assertEquals(USER_1_USERNAME, response.getUsername());
     }
 
     @Test
-    public void modify_succeeds() {
+    public void modify_succeeds() throws UserNotFoundException, AuthServiceException {
 
         /* mock */
         when(userRepository.findById(USER_1_ID))
@@ -114,8 +109,7 @@ public class UserServiceUnitTest extends AbstractUnitTest {
     }
 
     @Test
-    public void updatePassword_succeeds() throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
+    public void updatePassword_succeeds() throws UserNotFoundException {
 
         /* mock */
         doNothing()
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
index f5ad18b694081ed50b879d6690e2a85748b3bece..b3612fcc0fc306892db006bd12aa6ef483cf45a9 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java
@@ -1,34 +1,71 @@
 package at.tuwien.utils;
 
-import at.tuwien.exception.AuthServiceConnectionException;
-import at.tuwien.exception.AuthServiceException;
+import at.tuwien.api.keycloak.UserCreateDto;
+import at.tuwien.config.KeycloakConfig;
 import at.tuwien.exception.UserNotFoundException;
-import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.mapper.MetadataMapper;
+import jakarta.ws.rs.core.Response;
 import lombok.extern.log4j.Log4j2;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
 import java.util.UUID;
 
 @Log4j2
 @Component
 public class KeycloakUtils {
 
-    final static UUID realmId = UUID.fromString("82c39861-d877-4667-a0f3-4daa2ee230e0");
-
-    private final KeycloakGateway keycloakGateway;
+    private final Keycloak keycloak;
+    private final KeycloakConfig keycloakConfig;
+    private final MetadataMapper metadataMapper;
 
     @Autowired
-    public KeycloakUtils(KeycloakGateway keycloakGateway) {
-        this.keycloakGateway = keycloakGateway;
+    public KeycloakUtils(Keycloak keycloak, KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
+        this.keycloak = keycloak;
+        this.keycloakConfig = keycloakConfig;
+        this.metadataMapper = metadataMapper;
+    }
+
+    public void createUser(UUID ldapId, UserCreateDto data) {
+        final UserRepresentation user = metadataMapper.userCreateDtoToUserRepresentation(data);
+        user.singleAttribute("CUSTOM_ID", ldapId.toString());
+        try (Response response = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .create(user)) {
+            if (response.getStatus() != 201) {
+                log.warn("Failed to create user: {}", response.getStatus());
+            }
+        }
+        log.debug("Created user {} at auth service", data.getUsername());
     }
 
-    public void deleteUser(String username) throws AuthServiceException, AuthServiceConnectionException {
-        try {
-            final UUID userId = keycloakGateway.findByUsername(username).getId();
-            keycloakGateway.deleteUser(userId);
-        } catch (UserNotFoundException e) {
-            /* ignore */
+    public UUID getUserId(String username) throws UserNotFoundException {
+        final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .search(username);
+        if (users.isEmpty()) {
+            throw new UserNotFoundException("Failed to find user: " + username);
+        }
+        return UUID.fromString(users.get(0).getId());
+    }
+
+    public void deleteUser(String username) {
+        final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .search(username);
+        if (users.isEmpty()) {
+            log.warn("Failed to find user");
+            return;
+        }
+        try (Response response = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .delete(users.get(0).getId())) {
+            if (response.getStatus() != 200) {
+                log.error("Failed to delete user: {}", response.getStatus());
+            }
         }
     }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
index fe650589addb6ae15cb3d1d4d4b48f801054eca3..486db28e5945737e776da4b8f0aaf6d6d977715e 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java
@@ -2,8 +2,8 @@ package at.tuwien.validator;
 
 import at.tuwien.SortType;
 import at.tuwien.api.database.table.CreateTableDto;
-import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.database.table.columns.ColumnTypeDto;
+import at.tuwien.api.database.table.columns.CreateTableColumnDto;
 import at.tuwien.api.identifier.IdentifierSaveDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
@@ -70,6 +70,14 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         endpointValidator.validateDataParams(0L, 1L);
     }
 
+    @Test
+    public void validateOnlyAccess_system_succeeds() throws UserNotFoundException, NotAllowedException,
+            AccessNotFoundException {
+
+        /* test */
+        endpointValidator.validateOnlyAccess(DATABASE_1, USER_LOCAL_ADMIN_PRINCIPAL, false);
+    }
+
     @Test
     public void validateDataParams_bothNull_succeeds() throws PaginationException {
 
@@ -222,6 +230,20 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         endpointValidator.validateOnlyAccessOrPublic(DATABASE_1, USER_1_PRINCIPAL);
     }
 
+    @Test
+    public void validateOnlyWriteOwnOrWriteAllAccess_succeeds() throws DatabaseNotFoundException,
+            TableNotFoundException, AccessNotFoundException, NotAllowedException {
+
+        /* mock */
+        when(tableService.findById(DATABASE_1, TABLE_1_ID))
+                .thenReturn(TABLE_1);
+        when(accessService.find(eq(DATABASE_1), any(User.class)))
+                .thenReturn(DATABASE_1_USER_1_WRITE_ALL_ACCESS);
+
+        /* test */
+        endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(TABLE_1, USER_1);
+    }
+
     @Test
     public void validateOnlyWriteOwnOrWriteAllAccess_privateHasReadAccess_fails() throws DatabaseNotFoundException,
             TableNotFoundException, AccessNotFoundException {
@@ -323,6 +345,20 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         });
     }
 
+    @Test
+    public void validateOnlyPrivateDataHasRole_publicDatabase_succeeds() throws NotAllowedException {
+
+        /* test */
+        endpointValidator.validateOnlyPrivateDataHasRole(DATABASE_4, null, "nobody-role");
+    }
+
+    @Test
+    public void validateOnlyPrivateDataHasRole_privateDatabaseHasRole_succeeds() throws NotAllowedException {
+
+        /* test */
+        endpointValidator.validateOnlyPrivateDataHasRole(DATABASE_1, USER_1_PRINCIPAL, "find-database");
+    }
+
     @Test
     public void validateOnlyPrivateDataHasRole_privatePrincipalMissing_fails() {
 
@@ -491,6 +527,13 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest {
         assertTrue(endpointValidator.validatePublicationDate(request));
     }
 
+    @Test
+    public void validateOnlyMineOrWriteAccessOrHasRole_succeeds() {
+
+        /* test */
+        assertTrue(endpointValidator.validateOnlyMineOrWriteAccessOrHasRole(USER_1, USER_1_PRINCIPAL, null, "find-database"));
+    }
+
     @Test
     public void validateOnlyMineOrWriteAccessOrHasRole_noAccess_fails() {
 
diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
index 7ee28b34a4f2d662bb43979930732dec74da8a63..fb6df2007f2c5d50ab9ad744b622e248ea158cde 100644
--- a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
+++ b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json
@@ -27,7 +27,7 @@
   "oauth2DevicePollingInterval" : 5,
   "enabled" : true,
   "sslRequired" : "none",
-  "registrationAllowed" : false,
+  "registrationAllowed" : true,
   "registrationEmailAsUsername" : false,
   "rememberMe" : false,
   "verifyEmail" : true,
@@ -38,6 +38,7 @@
   "bruteForceProtected" : false,
   "permanentLockout" : false,
   "maxTemporaryLockouts" : 0,
+  "bruteForceStrategy" : "MULTIPLE",
   "maxFailureWaitSeconds" : 900,
   "minimumQuickLoginWaitSeconds" : 60,
   "waitIncrementSeconds" : 60,
@@ -73,7 +74,7 @@
       "description" : "${default-system-roles}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-database-view-data", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
+        "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "check-foreign-database-access", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
@@ -146,19 +147,11 @@
       "description" : "${default-table-handling}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ]
+        "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table", "update-table" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
-    }, {
-      "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3",
-      "name" : "view-database-view-data",
-      "description" : "${view-database-view-data}",
-      "composite" : false,
-      "clientRole" : false,
-      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
-      "attributes" : { }
     }, {
       "id" : "f5ea431a-9b2c-4195-bcb4-9511f38e4b44",
       "name" : "create-database-view",
@@ -219,7 +212,7 @@
       "description" : "${default-researcher-roles}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling" ]
+        "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling", "default-view-handling" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
@@ -264,6 +257,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "22449528-00c9-4e86-9400-4b8ae6fd8f4d",
+      "name" : "modify-view-visibility",
+      "description" : "${modify-view-visibility}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "c12c1f4e-186f-4153-a795-26e79fb623d6",
       "name" : "create-ontology",
@@ -296,6 +297,17 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "d75e7938-9d5e-4cb3-8c57-18a446867d3a",
+      "name" : "default-view-handling",
+      "description" : "${default-view-handling}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "delete-database-view", "update-database-view", "create-database-view", "modify-view-visibility", "find-database-view", "list-database-views" ]
+      },
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "535f1484-4514-4d24-8d97-e3f6c11a426b",
       "name" : "create-container",
@@ -390,17 +402,33 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "6ae766b0-b8b4-4067-a95d-c8576bc4ac77",
+      "name" : "update-table",
+      "description" : "${update-table}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "64c16bfb-2015-48ad-a23f-637ff24419cb",
       "name" : "default-query-handling",
       "description" : "${default-query-handling}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-database-view-data", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ]
+        "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "b05e9b2b-748d-490b-949b-e78655bf7805",
+      "name" : "check-foreign-database-access",
+      "description" : "${check-foreign-database-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "c047d521-cec3-4444-86c4-aef098489b7b",
       "name" : "delete-maintenance-message",
@@ -409,6 +437,14 @@
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "attributes" : { }
+    }, {
+      "id" : "df20b7d1-8d30-4a99-80eb-e8195fab0e76",
+      "name" : "update-database-view",
+      "description" : "${update-database-view}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
+      "attributes" : { }
     }, {
       "id" : "88f82262-be80-4d18-9fb4-5529da031f33",
       "name" : "system",
@@ -522,7 +558,7 @@
       "description" : "${default-container-handling}",
       "composite" : true,
       "composites" : {
-        "realm" : [ "find-container", "list-containers" ]
+        "realm" : [ "find-container" ]
       },
       "clientRole" : false,
       "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
@@ -902,7 +938,7 @@
         "composite" : true,
         "composites" : {
           "client" : {
-            "realm-management" : [ "query-realms", "view-identity-providers", "manage-identity-providers", "manage-authorization", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "query-groups", "create-client", "manage-clients", "manage-events", "impersonation", "view-events", "manage-realm" ]
+            "realm-management" : [ "query-realms", "manage-authorization", "manage-identity-providers", "view-identity-providers", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "create-client", "query-groups", "impersonation", "manage-clients", "manage-events", "view-events", "manage-realm" ]
           }
         },
         "clientRole" : true,
@@ -1203,12 +1239,13 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
     "fullScopeAllowed" : false,
     "nodeReRegistrationTimeout" : 0,
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   }, {
     "id" : "d3c4a04e-39ce-4549-a34a-11e25774cd96",
@@ -1233,6 +1270,7 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
@@ -1247,7 +1285,7 @@
       "consentRequired" : false,
       "config" : { }
     } ],
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   }, {
     "id" : "81ef0f59-a5ca-4be4-a1d1-0c32edf1cfd6",
@@ -1270,12 +1308,14 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
+      "client.use.lightweight.access.token.enabled" : "true",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
-    "fullScopeAllowed" : false,
+    "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : 0,
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   }, {
     "id" : "88694c91-753d-4c44-9740-ec9ac06bba45",
@@ -1298,6 +1338,7 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "true",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -1331,6 +1372,7 @@
     "frontchannelLogout" : true,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "oidc.ciba.grant.enabled" : "false",
       "client.secret.creation.time" : "1680085365",
       "backchannel.logout.session.required" : "true",
@@ -1342,6 +1384,38 @@
     "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : -1,
     "protocolMappers" : [ {
+      "id" : "266edf62-a19a-483b-b594-81428e4af792",
+      "name" : "orcid",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "ORCID",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "orcid",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "1a21798a-38b6-4df5-89f0-86942415246f",
+      "name" : "theme",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "THEME",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "theme",
+        "jsonType.label" : "String"
+      }
+    }, {
       "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
       "name" : "preferred_username",
       "protocol" : "openid-connect",
@@ -1355,27 +1429,77 @@
         "userinfo.token.claim" : "true"
       }
     }, {
-      "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
-      "name" : "aud",
+      "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a",
+      "name" : "affiliation",
       "protocol" : "openid-connect",
-      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "dbrepo",
+        "introspection.token.claim" : "true",
         "userinfo.token.claim" : "true",
+        "user.attribute" : "AFFILIATION",
         "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
-        "claim.name" : "aud",
-        "access.tokenResponse.claim" : "false"
+        "claim.name" : "affiliation",
+        "jsonType.label" : "String"
       }
     }, {
-      "id" : "0b4c644f-0cf0-4794-8395-d5d83009dabe",
+      "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88",
+      "name" : "language",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "LANGUAGE",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "language",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc",
       "name" : "uid",
       "protocol" : "openid-connect",
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
+        "aggregate.attrs" : "false",
         "introspection.token.claim" : "true",
+        "multivalued" : "false",
         "userinfo.token.claim" : "true",
         "user.attribute" : "CUSTOM_ID",
         "id.token.claim" : "true",
@@ -1384,9 +1508,26 @@
         "claim.name" : "uid",
         "jsonType.label" : "String"
       }
+    }, {
+      "id" : "c304ed2f-5952-4772-838d-91998a45f154",
+      "name" : "aud",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-hardcoded-claim-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "claim.value" : "account",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "aud",
+        "jsonType.label" : "String",
+        "access.tokenResponse.claim" : "false"
+      }
     } ],
-    "defaultClientScopes" : [ "roles", "attributes" ],
-    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+    "defaultClientScopes" : [ "roles", "basic" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
   }, {
     "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
     "clientId" : "rabbitmq-client",
@@ -1413,6 +1554,7 @@
     "frontchannelLogout" : true,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
       "oidc.ciba.grant.enabled" : "false",
       "client.secret.creation.time" : "1680000860",
       "backchannel.logout.session.required" : "true",
@@ -1430,12 +1572,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "false",
         "user.attribute" : "username",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "client_id",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "false"
       }
     }, {
       "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
@@ -1444,15 +1586,15 @@
       "protocolMapper" : "oidc-hardcoded-claim-mapper",
       "consentRequired" : false,
       "config" : {
-        "claim.value" : "rabbitmq",
-        "userinfo.token.claim" : "false",
         "id.token.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "aud",
+        "claim.value" : "rabbitmq",
+        "userinfo.token.claim" : "false",
         "access.tokenResponse.claim" : "false"
       }
     } ],
-    "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management", "basic" ],
     "optionalClientScopes" : [ "rabbitmq.read:*/*", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "roles", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
   }, {
     "id" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930",
@@ -1475,6 +1617,7 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "true",
       "post.logout.redirect.uris" : "+"
     },
     "authenticationFlowBindingOverrides" : { },
@@ -1505,11 +1648,13 @@
     "frontchannelLogout" : false,
     "protocol" : "openid-connect",
     "attributes" : {
+      "realm_client" : "false",
+      "client.use.lightweight.access.token.enabled" : "true",
       "post.logout.redirect.uris" : "+",
       "pkce.code.challenge.method" : "S256"
     },
     "authenticationFlowBindingOverrides" : { },
-    "fullScopeAllowed" : false,
+    "fullScopeAllowed" : true,
     "nodeReRegistrationTimeout" : 0,
     "protocolMappers" : [ {
       "id" : "c4d54410-3f22-4259-9571-94da2c43b752",
@@ -1518,15 +1663,15 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ],
-    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
+    "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
     "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
   } ],
   "clientScopes" : [ {
@@ -1547,8 +1692,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${emailScopeConsentText}"
+      "consent.screen.text" : "${emailScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
@@ -1557,12 +1702,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "emailVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
@@ -1571,12 +1716,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "email",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "email",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1586,8 +1731,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${profileScopeConsentText}"
+      "consent.screen.text" : "${profileScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
@@ -1596,12 +1741,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "preferred_username",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
@@ -1610,12 +1755,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "gender",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "gender",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
@@ -1624,12 +1769,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "birthdate",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "birthdate",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
@@ -1649,12 +1794,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "profile",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "profile",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
@@ -1663,12 +1808,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "updatedAt",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "updated_at",
-        "jsonType.label" : "long"
+        "jsonType.label" : "long",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "841ea785-26ab-429a-a420-09ce3948924d",
@@ -1677,12 +1822,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "lastName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "family_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
@@ -1691,12 +1836,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "website",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "website",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "475f071d-5149-4379-b928-76482f5f519c",
@@ -1705,12 +1850,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "zoneinfo",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "zoneinfo",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
@@ -1719,12 +1864,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "middleName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "middle_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
@@ -1733,12 +1878,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "picture",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "picture",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
@@ -1747,12 +1892,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "locale",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "locale",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
@@ -1761,12 +1906,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "firstName",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "given_name",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
@@ -1775,12 +1920,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "nickname",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "nickname",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1814,12 +1959,12 @@
       "protocolMapper" : "oidc-usermodel-property-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "username",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "upn",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1861,8 +2006,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${phoneScopeConsentText}"
+      "consent.screen.text" : "${phoneScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
@@ -1871,12 +2016,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumber",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number",
-        "jsonType.label" : "String"
+        "jsonType.label" : "String",
+        "userinfo.token.claim" : "true"
       }
     }, {
       "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
@@ -1885,12 +2030,12 @@
       "protocolMapper" : "oidc-usermodel-attribute-mapper",
       "consentRequired" : false,
       "config" : {
-        "userinfo.token.claim" : "true",
         "user.attribute" : "phoneNumberVerified",
         "id.token.claim" : "true",
         "access.token.claim" : "true",
         "claim.name" : "phone_number_verified",
-        "jsonType.label" : "boolean"
+        "jsonType.label" : "boolean",
+        "userinfo.token.claim" : "true"
       }
     } ]
   }, {
@@ -1900,8 +2045,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "false",
-      "consent.screen.text" : ""
+      "consent.screen.text" : "",
+      "display.on.consent.screen" : "false"
     },
     "protocolMappers" : [ {
       "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
@@ -1981,6 +2126,61 @@
       "gui.order" : "",
       "consent.screen.text" : ""
     }
+  }, {
+    "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6",
+    "name" : "service_account",
+    "description" : "Specific scope for a client enabled for service accounts",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512",
+      "name" : "Client IP Address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientAddress",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientAddress",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a",
+      "name" : "Client Host",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "clientHost",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "clientHost",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae",
+      "name" : "Client ID",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "client_id",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "client_id",
+        "jsonType.label" : "String"
+      }
+    } ]
   }, {
     "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
     "name" : "offline_access",
@@ -1997,8 +2197,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "true",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${addressScopeConsentText}"
+      "consent.screen.text" : "${addressScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
@@ -2029,6 +2229,41 @@
       "gui.order" : "",
       "consent.screen.text" : ""
     }
+  }, {
+    "id" : "ba11267a-478b-4b32-872f-4eb2d125d116",
+    "name" : "basic",
+    "description" : "OpenID Connect scope for add all basic claims to the token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "1445e14f-49b0-4666-8ddc-691493c24ad9",
+      "name" : "sub",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-sub-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "introspection.token.claim" : "true",
+        "access.token.claim" : "true"
+      }
+    }, {
+      "id" : "846f1ef0-2b86-4e07-9d25-691d25af5fce",
+      "name" : "auth_time",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.session.note" : "AUTH_TIME",
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "true",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "auth_time",
+        "jsonType.label" : "long"
+      }
+    } ]
   }, {
     "id" : "37f61543-dad7-4a82-8e10-77acdd1eefdc",
     "name" : "roles",
@@ -2036,8 +2271,8 @@
     "protocol" : "openid-connect",
     "attributes" : {
       "include.in.token.scope" : "false",
-      "display.on.consent.screen" : "true",
-      "consent.screen.text" : "${rolesScopeConsentText}"
+      "consent.screen.text" : "${rolesScopeConsentText}",
+      "display.on.consent.screen" : "true"
     },
     "protocolMappers" : [ {
       "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
@@ -2053,11 +2288,15 @@
       "protocolMapper" : "oidc-usermodel-realm-role-mapper",
       "consentRequired" : false,
       "config" : {
+        "introspection.token.claim" : "true",
+        "userinfo.token.claim" : "false",
+        "multivalued" : "true",
         "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "lightweight.claim" : "false",
         "access.token.claim" : "true",
         "claim.name" : "realm_access.roles",
-        "jsonType.label" : "String",
-        "multivalued" : "true"
+        "jsonType.label" : "String"
       }
     }, {
       "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
@@ -2074,7 +2313,7 @@
       }
     } ]
   } ],
-  "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management" ],
+  "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management", "basic" ],
   "defaultOptionalClientScopes" : [ "rabbitmq.write:*/*", "offline_access", "rabbitmq.configure:*/*", "roles", "role_list", "address", "phone", "acr", "microprofile-jwt", "email", "attributes", "profile", "rabbitmq.read:*/*", "web-origins" ],
   "browserSecurityHeaders" : {
     "contentSecurityPolicyReportOnly" : "",
@@ -2087,6 +2326,10 @@
     "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
   },
   "smtpServer" : { },
+  "loginTheme" : "keycloak",
+  "accountTheme" : "",
+  "adminTheme" : "",
+  "emailTheme" : "",
   "eventsEnabled" : false,
   "eventsListeners" : [ "jboss-logging" ],
   "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
@@ -2136,7 +2379,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2162,11 +2405,11 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper" ]
       }
     } ],
     "org.keycloak.userprofile.UserProfileProvider" : [ {
-      "id" : "fb763636-e1ea-49c7-adca-ea105cdec4ad",
+      "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
       "providerId" : "declarative-user-profile",
       "subComponents" : { },
       "config" : {
@@ -2185,17 +2428,6 @@
         "priority" : [ "100" ],
         "algorithm" : [ "RSA-OAEP" ]
       }
-    }, {
-      "id" : "230cb681-9ceb-4b1b-8a4c-929a11b08de0",
-      "name" : "hmac-generated-hs512",
-      "providerId" : "hmac-generated",
-      "subComponents" : { },
-      "config" : {
-        "kid" : [ "8a489935-9a95-459b-9059-59b438ef0fa8" ],
-        "secret" : [ "xSCVgBlrLPWoF54gKQdR7BqXlfNaCD43xtS_ZgQRC0tGNAbqhy2Q9y8LdD2IR7K__8VGaDGYtyZayopgTebhDBb4gHDjDOBX7flhFYRrm0G3aTIuCIyFG-bPULwmyP_oHeC6tjwdQhqx5G0tE2mQQqPC9dDZuUA5I7QREIGK8cI" ],
-        "priority" : [ "100" ],
-        "algorithm" : [ "HS512" ]
-      }
     }, {
       "id" : "28ca0b6d-b2e2-4785-b04b-2391e6344e30",
       "name" : "aes-generated",
@@ -2212,8 +2444,8 @@
       "providerId" : "hmac-generated",
       "subComponents" : { },
       "config" : {
-        "kid" : [ "5034d264-cb50-4006-a59e-2ce636eb5f38" ],
-        "secret" : [ "ToVIw-a4IE-Yp9JpP8ztb8NAICYO8CT3tUiDPT6DdiBcgzKJ9Ym9vspxGVdmPceX3mAgbnGLAcTx1PkInSVrbZs-tX9QXFwdlyGbewhKiNpH8wEg32Wk4GuUDpTv8JCsymgWyQBY681jvIMv05eCoK2QWpqCzcgP828KM5peCzo" ],
+        "kid" : [ "7f9f9054-5697-4f60-bdc8-67e3bd0f4db6" ],
+        "secret" : [ "1SCIY20z3AbAHCL28LuJfBU-7zfsZv5dacgliUeGdRW_WK3vH9fJUpPu1f7iDrdlhF7YQmHxLXsWjxhQId4ShI7QBdgKCArHWqi0GeH37oNXfZFg_uv-K_3JSfxfGBRu5jpRQhhSBxESZWsFVkskhxWUvNe6b5l9dFbMIif72rI" ],
         "priority" : [ "100" ],
         "algorithm" : [ "HS256" ]
       }
@@ -2228,12 +2460,23 @@
         "certificate" : [ "MIICmzCCAYMCBgGG3GWyBTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqqcdDYFZZb28M0tEJzEP77FmD/Xqioyj9zWX6VwUSOMAgmMmn8eqs9hT9T0a+q4YTo9tUW1PNbUpwprA5b4Uk04DcIajxDVMUR/PjcHytmkqwVskq9AZW/Vngdoo+8tSbuIybwe/3Vwt266hbHpDcM97a+DXcYooRl7tQWCEX7RP27wQrMD9epDQ6IgKayZg9vC9/03dsIqwH9jXQRiZlFvwiEKhX2aY7lPGBaCK414JO00K/Z49iov9TRa/IYVbSt5qwgrx6DcqsBSPwOnI6A85UGfeUEZ/7coVJiL7RvBlsllapsL9eWTbQajVh94k9Ei3sibEPbtH+U2OAM78zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASnN1Cuif1sdfEK2kWAURSXGJCohCROLWdKFjaeHPRaEfpbFJsgxW0Yj3nwX5O3bUlOWoTyENwnXSsXMQsqnNi+At32CKaKO8+AkhAbgQL9F0B+KeJwmYv3cUj5N/LYkJjBvZBzUZ4Ugu5dcxH0k7AktLAIwimkyEnxTNolOA3UyrGGpREr8MCKWVr10RFuOpF/0CsJNNwbHXzalO9D756EUcRWZ9VSg6QVNso0YYRKTnILWDn9hcTRnqGy3SHo3anFTqQZ+BB57YbgFWy6udC0LYRB3zdp6zNti87eu/VEymiDY/mmo1AB8Tm0b6vxFz4AKcL3ax5qS6YnZ9efSzk=" ],
         "priority" : [ "100" ]
       }
+    }, {
+      "id" : "addbae10-c6ae-4735-851f-7a5ea035ce25",
+      "name" : "hmac-generated-hs512",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "352d0ea1-8218-42b5-ab78-e2ca56cf6a95" ],
+        "secret" : [ "_kr6EZOZ8IKqPWgJltHAAsQ34wCIGPs8oOQLYWwJrSIH7Qie3CEVKZnICyBP1goR-QgUtg25tR8Qu5MkvYkb8assJ8Iok5x_8iYCR4Txkf_mS-emrlAtQajlIjmOfNBtx704dTnZlP9rWzqpW6mrpeiOaiCw1K0XCpY5C_ZjXKw" ],
+        "priority" : [ "100" ],
+        "algorithm" : [ "HS512" ]
+      }
     } ]
   },
   "internationalizationEnabled" : false,
   "supportedLocales" : [ ],
   "authenticationFlows" : [ {
-    "id" : "88e5d526-2298-413c-a904-133ad839d47f",
+    "id" : "259dd7b6-01b7-433a-bda4-028857151ecd",
     "alias" : "Account verification options",
     "description" : "Method with which to verity the existing account",
     "providerId" : "basic-flow",
@@ -2255,7 +2498,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "a690c715-fbae-4c20-b680-bd4010718761",
+    "id" : "542ca1d7-9627-4102-b843-98837ce433fb",
     "alias" : "Browser - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2277,7 +2520,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ad6d407e-c73e-4439-baf3-d7c99c6cb6ad",
+    "id" : "4f153b98-6851-440b-a022-0a14e67a9b2f",
     "alias" : "Direct Grant - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2299,7 +2542,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "e5d03405-e10a-408a-adb2-41dbb4f24515",
+    "id" : "3d791b35-d35c-40b2-bb3e-e806d72b27ee",
     "alias" : "First broker login - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2321,7 +2564,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "96b93843-62d0-44f1-84dd-21cc5f95f523",
+    "id" : "9b746104-9371-4c3f-b69f-9322cead1b08",
     "alias" : "Handle Existing Account",
     "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
     "providerId" : "basic-flow",
@@ -2343,7 +2586,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "088f4051-36ab-4952-a4f2-4ba53c408083",
+    "id" : "7a164efe-c97b-4fbb-950d-7745359ba9a4",
     "alias" : "Reset - Conditional OTP",
     "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
     "providerId" : "basic-flow",
@@ -2365,7 +2608,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "05f37bb2-779d-4e3f-ad1b-f6eb33bb3de4",
+    "id" : "4fdc5e1b-1b55-4662-8360-67d75fa22677",
     "alias" : "User creation or linking",
     "description" : "Flow for the existing/non-existing user alternatives",
     "providerId" : "basic-flow",
@@ -2388,7 +2631,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "300a5647-7d2c-4348-9f1f-51504bfda1c4",
+    "id" : "75893341-c338-44d8-ae27-a3fc7bfe8f2d",
     "alias" : "Verify Existing Account by Re-authentication",
     "description" : "Reauthentication of existing account",
     "providerId" : "basic-flow",
@@ -2410,7 +2653,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "26afc672-314b-4ad9-9711-7aaeafd7c00c",
+    "id" : "89626b76-f4cf-4c46-934c-4408c225a44b",
     "alias" : "browser",
     "description" : "browser based authentication",
     "providerId" : "basic-flow",
@@ -2446,7 +2689,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "9b301f6c-eda7-4da0-ba09-1a6454ff910d",
+    "id" : "4112115a-e7a7-44c2-9af5-65d538e4ba0d",
     "alias" : "clients",
     "description" : "Base authentication for clients",
     "providerId" : "client-flow",
@@ -2482,7 +2725,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "6e54f1be-dbad-4b6d-8eee-8e048d413c63",
+    "id" : "f82a9b0a-2c0a-4cb1-96b2-6c78b0b1f14f",
     "alias" : "direct grant",
     "description" : "OpenID Connect Resource Owner Grant",
     "providerId" : "basic-flow",
@@ -2511,7 +2754,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "31da4b94-03c4-4d79-9ac3-5df1445c0781",
+    "id" : "3614e155-e8ce-4958-98fb-a27e4706cc70",
     "alias" : "docker auth",
     "description" : "Used by Docker clients to authenticate against the IDP",
     "providerId" : "basic-flow",
@@ -2526,7 +2769,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "2e16651d-681f-4d9b-9dd4-9acdb465cd43",
+    "id" : "506f9b96-5002-47c0-96e3-3830a0fcfa26",
     "alias" : "first broker login",
     "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
     "providerId" : "basic-flow",
@@ -2549,7 +2792,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "da109a26-fefa-48a4-ae8e-1d49627c2db8",
+    "id" : "4b7a7e91-36db-4b27-8e2d-01a04a822980",
     "alias" : "forms",
     "description" : "Username, password, otp and other auth forms.",
     "providerId" : "basic-flow",
@@ -2571,7 +2814,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "4c983c77-241f-41c5-8b8a-e2cd6fc08914",
+    "id" : "04c2fe01-5076-4aa4-9596-4efb4004195f",
     "alias" : "registration",
     "description" : "registration flow",
     "providerId" : "basic-flow",
@@ -2587,7 +2830,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "d62c8dd6-633c-408a-aa99-43071510efb4",
+    "id" : "d12f77e1-7733-44a2-98ff-fd75c784d721",
     "alias" : "registration form",
     "description" : "registration form",
     "providerId" : "form-flow",
@@ -2616,7 +2859,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "c8ca5be7-e76d-4e16-b5ca-3ced99d92dbb",
+    "id" : "91f6048c-a376-4809-8f37-c8d7a517830c",
     "alias" : "reset credentials",
     "description" : "Reset credentials for a user if they forgot their password or something",
     "providerId" : "basic-flow",
@@ -2652,7 +2895,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "389c1c37-e8af-4610-a507-e1257f55b954",
+    "id" : "7b8fb487-53b8-4533-a696-76bc05256cb1",
     "alias" : "saml ecp",
     "description" : "SAML ECP Profile Authentication Flow",
     "providerId" : "basic-flow",
@@ -2668,13 +2911,13 @@
     } ]
   } ],
   "authenticatorConfig" : [ {
-    "id" : "d66ca9d0-1645-4c84-abfe-c0a696f17de4",
+    "id" : "48372696-0579-45e5-b074-5e8dbdbbe7d6",
     "alias" : "create unique user config",
     "config" : {
       "require.password.update.after.registration" : "false"
     }
   }, {
-    "id" : "061cc6b8-90be-4423-9bf9-974ead709b5d",
+    "id" : "08df3b83-e522-42a7-9e24-9028b960bf39",
     "alias" : "review profile config",
     "config" : {
       "update.profile.on.first.login" : "missing"
@@ -2785,10 +3028,12 @@
     "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
     "parRequestUriLifespan" : "60",
     "clientSessionMaxLifespan" : "0",
+    "organizationsEnabled" : "false",
     "shortVerificationUri" : ""
   },
-  "keycloakVersion" : "24.0.5",
+  "keycloakVersion" : "26.0.4",
   "userManagedAccessAllowed" : false,
+  "organizationsEnabled" : false,
   "clientProfiles" : {
     "profiles" : [ ]
   },
diff --git a/dbrepo-metadata-service/services/pom.xml b/dbrepo-metadata-service/services/pom.xml
index 0ec2d62d1dfa663ce71b468e16e74bc1fb015c40..d1b8f9a7026e77f2235c580f0149f4dac17df779 100644
--- a/dbrepo-metadata-service/services/pom.xml
+++ b/dbrepo-metadata-service/services/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <artifactId>dbrepo-metadata-service</artifactId>
         <groupId>at.tuwien</groupId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-services</artifactId>
     <name>dbrepo-metadata-service-services</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
index b9fea2b54b1c242f58dbc0cd578e9dff328ba49c..d6535bad491b18744afecbe4fdc4792dfd3e7f33 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java
@@ -1,7 +1,6 @@
 package at.tuwien.auth;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.exception.*;
 import at.tuwien.gateway.KeycloakGateway;
 import jakarta.servlet.ServletException;
 import lombok.extern.log4j.Log4j2;
@@ -34,8 +33,7 @@ public class BasicAuthenticationProvider implements AuthenticationManager {
             final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken());
             log.debug("set basic auth principal: {}", userDetails);
             return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
-        } catch (ServletException | CredentialsInvalidException | AccountNotSetupException |
-                 AuthServiceConnectionException e) {
+        } catch (ServletException e) {
             throw new BadCredentialsException("Failed to authenticate with authentication service", e);
         }
     }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
index 835b7245d1ef2ca017375990dd77c20693f3ef6f..b0edc929ed0097ce94e65153707dc47406f0f3c9 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java
@@ -2,9 +2,6 @@ package at.tuwien.auth;
 
 import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.config.GatewayConfig;
-import at.tuwien.exception.AccountNotSetupException;
-import at.tuwien.exception.AuthServiceConnectionException;
-import at.tuwien.exception.CredentialsInvalidException;
 import at.tuwien.gateway.KeycloakGateway;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.http.HttpHeaders;
@@ -33,15 +30,10 @@ public class InternalRequestInterceptor implements ClientHttpRequestInterceptor
             throws IOException {
         final HttpHeaders headers = request.getHeaders();
         headers.setAccept(List.of(MediaType.APPLICATION_JSON));
-        try {
-            final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(),
-                    gatewayConfig.getSystemPassword());
-            headers.setBearerAuth(token.getAccessToken());
-            log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername());
-            return execution.execute(request, body);
-        } catch (AuthServiceConnectionException | CredentialsInvalidException | AccountNotSetupException e) {
-            log.error("Failed to obtain token for internal user: {}", gatewayConfig.getSystemUsername());
-            throw new IOException("Failed to obtain token for internal user", e);
-        }
+        final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(),
+                gatewayConfig.getSystemPassword());
+        headers.setBearerAuth(token.getAccessToken());
+        log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername());
+        return execution.execute(request, body);
     }
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
index a24bbf41b8168b6e5c9ffef70c1b7bbbd6f5c674..4b62b61dcba2e06f9847d9eb20042b1f535bbc8d 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java
@@ -1,12 +1,11 @@
 package at.tuwien.config;
 
-import at.tuwien.interceptor.KeycloakInterceptor;
 import lombok.Getter;
+import org.keycloak.admin.client.Keycloak;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 @Getter
 @Configuration
@@ -27,17 +26,15 @@ public class KeycloakConfig {
     @Value("${dbrepo.keycloak.clientSecret}")
     private String keycloakClientSecret;
 
+    private final String realm = "dbrepo";
+
     @Bean
     public RestTemplate restTemplate() {
         return new RestTemplate();
     }
 
-    @Bean("keycloakRestTemplate")
-    public RestTemplate brokerRestTemplate() {
-        final RestTemplate restTemplate = new RestTemplate();
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
-        restTemplate.getInterceptors()
-                .add(new KeycloakInterceptor(restTemplate(), keycloakUsername, keycloakPassword, keycloakEndpoint));
-        return restTemplate;
+    @Bean
+    public Keycloak keycloak() {
+        return Keycloak.getInstance(keycloakEndpoint, "master", keycloakUsername, keycloakPassword, "admin-cli");
     }
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
index 94ea986f78727a6fdc927b4e7ebb25ca6f0616bd..cd5fd08a7ef64e88134a1fc19aa0840ad1e98020 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java
@@ -1,37 +1,26 @@
 package at.tuwien.gateway;
 
 import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserCreateDto;
-import at.tuwien.api.keycloak.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
-import at.tuwien.exception.*;
+import at.tuwien.api.user.UserUpdateDto;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.UserNotFoundException;
+import org.keycloak.representations.idm.UserRepresentation;
 
 import java.util.UUID;
 
 public interface KeycloakGateway {
 
-    TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException,
-            CredentialsInvalidException, AccountNotSetupException;
+    TokenDto obtainUserToken(String username, String password);
 
-    TokenDto refreshUserToken(String refreshToken) throws AuthServiceConnectionException,
-            CredentialsInvalidException;
-
-    /**
-     * Creates a user at the Authentication Service with given credentials.
-     *
-     * @param data The user credentials.
-     * @throws UserExistsException      The user already exists at the Authentication Service.
-     * @throws EmailExistsException The user email already exists in the metadata database.
-     */
-    void createUser(UserCreateDto data) throws AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException, UserExistsException;
+    UserRepresentation findByUsername(String username) throws UserNotFoundException;
 
     /**
      * Deletes a user at the Authentication Service with given user id.
      *
      * @param id The user id.
      */
-    void deleteUser(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException;
+    void deleteUser(UUID id) throws UserNotFoundException;
 
     /**
      * Update the credentials for a given user.
@@ -39,17 +28,7 @@ public interface KeycloakGateway {
      * @param id       The user id.
      * @param password The user credential.
      */
-    void updateUserCredentials(UUID id, UserPasswordDto password) throws AuthServiceException,
-            AuthServiceConnectionException, UserNotFoundException;
-
-    /**
-     * Finds a user in the metadata database by given username.
-     *
-     * @param username The user username.
-     * @return The updated user.
-     */
-    UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException;
+    void updateUserCredentials(UUID id, UserPasswordDto password) throws UserNotFoundException;
 
-    UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException;
+    void updateUser(UUID id, UserUpdateDto data) throws AuthServiceException, UserNotFoundException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
index bce9d6e264b5283864c4e0ce4d2a157bd3d7dab4..af54651d6c36197e136134003291ea88f5df2a49 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java
@@ -1,232 +1,128 @@
 package at.tuwien.gateway.impl;
 
-import at.tuwien.api.auth.KeycloakErrorDto;
-import at.tuwien.api.keycloak.*;
+import at.tuwien.api.keycloak.TokenDto;
 import at.tuwien.api.user.UserPasswordDto;
+import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.config.KeycloakConfig;
-import at.tuwien.exception.*;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.UserNotFoundException;
 import at.tuwien.gateway.KeycloakGateway;
 import at.tuwien.mapper.MetadataMapper;
+import jakarta.ws.rs.BadRequestException;
+import jakarta.ws.rs.ForbiddenException;
+import jakarta.ws.rs.NotFoundException;
+import jakarta.ws.rs.core.Response;
 import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.http.*;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.KeycloakBuilder;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.springframework.stereotype.Service;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
+import java.util.List;
 import java.util.UUID;
 
 @Log4j2
 @Service
 public class KeycloakGatewayImpl implements KeycloakGateway {
 
-    private final RestTemplate restTemplate;
-    private final RestTemplate keycloakRestTemplate;
+    private final Keycloak keycloak;
     private final KeycloakConfig keycloakConfig;
     private final MetadataMapper metadataMapper;
 
-    public KeycloakGatewayImpl(@Qualifier("restTemplate") RestTemplate restTemplate,
-                               @Qualifier("keycloakRestTemplate") RestTemplate keycloakRestTemplate,
-                               KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakConfig.getKeycloakEndpoint()));
-        this.restTemplate = restTemplate;
-        this.keycloakRestTemplate = keycloakRestTemplate;
+    public KeycloakGatewayImpl(Keycloak keycloak, KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) {
+        this.keycloak = keycloak;
         this.keycloakConfig = keycloakConfig;
         this.metadataMapper = metadataMapper;
     }
 
     @Override
-    public TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException,
-            CredentialsInvalidException, AccountNotSetupException {
-        final HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
-        final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
-        payload.add("username", username);
-        payload.add("password", password);
-        payload.add("grant_type", "password");
-        payload.add("scope", "openid roles");
-        payload.add("client_id", keycloakConfig.getKeycloakClient());
-        payload.add("client_secret", keycloakConfig.getKeycloakClientSecret());
-        final String path = "/realms/dbrepo/protocol/openid-connect/token";
-        log.trace("obtain user token at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<TokenDto> response;
-        try {
-            response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to obtain user token: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.BadRequest e) {
-            final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
-            if (error != null && error.getError().equals("invalid_grant")) {
-                log.error("Failed to obtain user token: {}", error.getErrorDescription());
-                throw new AccountNotSetupException(error.getErrorDescription());
-            }
-            log.error("Failed to obtain user token: bad request");
-            throw new CredentialsInvalidException("Bad request", e);
-        } catch (HttpClientErrorException.Unauthorized e) {
-            log.error("Failed to obtain user token: invalid credentials");
-            throw new CredentialsInvalidException("Invalid credentials", e);
+    public TokenDto obtainUserToken(String username, String password) {
+        try (Keycloak userKeycloak = KeycloakBuilder.builder()
+                .serverUrl(keycloakConfig.getKeycloakEndpoint())
+                .realm(keycloakConfig.getRealm())
+                .grantType(OAuth2Constants.PASSWORD)
+                .clientId(keycloakConfig.getKeycloakClient())
+                .clientSecret(keycloakConfig.getKeycloakClientSecret())
+                .username(username)
+                .password(password)
+                .build()) {
+            return metadataMapper.accessTokenResponseToTokenDto(userKeycloak.tokenManager()
+                    .getAccessToken());
         }
-        return response.getBody();
     }
 
     @Override
-    public TokenDto refreshUserToken(String refreshToken) throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-        final HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
-        final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
-        payload.add("refresh_token", refreshToken);
-        payload.add("grant_type", "refresh_token");
-        payload.add("client_id", keycloakConfig.getKeycloakClient());
-        payload.add("client_secret", keycloakConfig.getKeycloakClientSecret());
-        final String path = "/realms/dbrepo/protocol/openid-connect/token";
-        log.trace("refresh user token at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<TokenDto> response;
-        try {
-            response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to refresh user token: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.Unauthorized e) {
-            log.error("Failed to refresh user token: invalid credentials");
-            throw new CredentialsInvalidException("Invalid credentials", e);
-        } catch (HttpClientErrorException.BadRequest e) {
-            if (e.getMessage() != null && e.getMessage().contains("Session not active")) {
-                log.error("Failed to refresh user token: inactive session", e);
-                throw new CredentialsInvalidException("Inactive session", e);
-            }
-            log.error("Failed to refresh user token: unexpected response: {}", e.getMessage(), e);
-            throw new CredentialsInvalidException("Unexpected response: " + e.getMessage(), e);
+    public UserRepresentation findByUsername(String username) throws UserNotFoundException {
+        final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .search(username);
+        if (users.isEmpty()) {
+            log.error("Failed to find user with username {}", username);
+            throw new UserNotFoundException("Failed to find user");
         }
-        return response.getBody();
+        return users.get(0);
     }
 
     @Override
-    public void createUser(UserCreateDto data) throws AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException, UserExistsException {
-        final String path = "/admin/realms/dbrepo/users";
-        log.trace("create user at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<Void> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to create user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.Conflict e) {
-            if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) {
-                final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
-                if (error != null && error.getErrorMessage().contains("same email")) {
-                    log.error("Failed to create user: email exists: {}", e.getMessage());
-                    throw new EmailExistsException("E-Mail exists", e);
-                }
+    public void deleteUser(UUID id) throws UserNotFoundException {
+        try (Response response = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .delete(String.valueOf(id))) {
+            if (response.getStatus() == 404) {
+                log.error("Failed to delete user: not found");
+                throw new UserNotFoundException("Failed to delete user: not found");
             }
-            log.error("Failed to create user: user exists: {}", e.getMessage());
-            throw new UserExistsException("User exists", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
-            log.error("Failed to create user: unexpected status: {}", response.getStatusCode().value());
-            throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value());
-        }
-        log.debug("Created user {} at auth service", data.getUsername());
-    }
-
-    @Override
-    public void deleteUser(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException {
-        final String path = "/admin/realms/dbrepo/users/" + id;
-        log.trace("delete user at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<Void> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to delete user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.NotFound e) {
-            log.error("Failed to delete user: user not found: {}", e.getMessage());
-            throw new UserNotFoundException("User not found", e);
-        } catch (Exception e) {
-            log.error("Failed to delete user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
-            log.error("Failed to delete user: unexpected response");
-            throw new AuthServiceException("Unexpected result");
         }
         log.info("Deleted user {} at auth service", id);
     }
 
     @Override
-    public void updateUserCredentials(UUID id, UserPasswordDto data) throws AuthServiceException,
-            AuthServiceConnectionException, UserNotFoundException {
-        final UpdateCredentialsDto payload = metadataMapper.passwordToUpdateCredentialsDto(data.getPassword());
-        final String path = "/admin/realms/dbrepo/users/" + id;
-        log.trace("update user credentials at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<Void> response;
+    public void updateUserCredentials(UUID id, UserPasswordDto data) throws UserNotFoundException {
+        final CredentialRepresentation credential = new CredentialRepresentation();
+        credential.setTemporary(false);
+        credential.setValue(data.getPassword());
+        credential.setType(CredentialRepresentation.PASSWORD);
         try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(payload), Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to update user credentials: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.NotFound e) {
-            log.error("Failed to update user credentials: user not found: {}", e.getMessage());
-            throw new UserNotFoundException("User not found", e);
-        } catch (Exception e) {
-            log.error("Failed to update user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
-            log.error("Failed to update user: unexpected status: {}", response.getStatusCode().value());
-            throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value());
+            keycloak.realm(keycloakConfig.getRealm())
+                    .users()
+                    .get(String.valueOf(id))
+                    .resetPassword(credential);
+        } catch (NotFoundException e) {
+            log.error("Failed to update user password: not found");
+            throw new UserNotFoundException("Failed to update user password: not found", e);
         }
         log.info("Updated user {} password at auth service", id);
     }
 
     @Override
-    public UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
-        final String path = "/admin/realms/dbrepo/users/?username=" + username;
-        log.trace("find user by username at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<UserDto[]> response;
+    public void updateUser(UUID id, UserUpdateDto data) throws AuthServiceException, UserNotFoundException {
+        final UserResource resource = keycloak.realm(keycloakConfig.getRealm())
+                .users()
+                .get(String.valueOf(id));
+        UserRepresentation user;
         try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto[].class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to find user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (Exception e) {
-            log.error("Failed to find user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
+            user = resource.toRepresentation();
+        } catch (NotFoundException e) {
+            log.error("Failed to update user: not found: {}", e.getMessage());
+            throw new UserNotFoundException("Failed to update user: not found", e);
         }
-        final UserDto[] body = response.getBody();
-        if (body == null || body.length != 1) {
-            log.error("Failed to find user with username {}", username);
-            throw new UserNotFoundException("Failed to find user with username " + username);
-        }
-        return body[0];
-    }
-
-    @Override
-    public UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException {
-        final String path = "/admin/realms/dbrepo/users/" + id;
-        log.trace("find user by id at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path);
-        final ResponseEntity<UserDto> response;
+        user.setFirstName(data.getFirstname());
+        user.setLastName(data.getLastname());
+        user.singleAttribute("THEME", data.getTheme());
+        user.singleAttribute("ORCID", data.getOrcid());
+        user.singleAttribute("LANGUAGE", data.getLanguage());
+        user.singleAttribute("AFFILIATION", data.getAffiliation());
+        log.trace("update user: {}", data);
         try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to find user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.NotFound e) {
-            log.error("Failed to find user: not found: {}", e.getMessage());
-            throw new UserNotFoundException("User not found");
-        } catch (Exception e) {
-            log.error("Failed to find user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
+            resource.update(user);
+        } catch (ForbiddenException e) {
+            log.error("Failed to update user: forbidden: {}", e.getMessage());
+            throw new AuthServiceException("Failed to update user: forbidden", e);
         }
-        return response.getBody();
+        log.info("Updated user {} attributes at auth service", id);
     }
 
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
index a288d1d6e08488de5935e6d0af776fb157c8531e..75b647bf954fd638dfde8ffa8b7f650d03ce7c49 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
@@ -1,30 +1,14 @@
 package at.tuwien.service;
 
-import at.tuwien.api.auth.LoginRequestDto;
-import at.tuwien.api.auth.CreateUserDto;
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.*;
-
-import java.util.UUID;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.CredentialsInvalidException;
+import at.tuwien.exception.UserNotFoundException;
 
 public interface AuthenticationService {
 
-    /**
-     * Create a user at the Authentication Service with given credentials.
-     *
-     * @param data The credentials.
-     * @return The user, if successful.
-     * @throws UserExistsException        The user already exists at the auth database.
-     * @throws AuthServiceException           The auth service responded with unexpected behavior.
-     * @throws AuthServiceConnectionException The connection with the auth service could not be established.
-     * @throws EmailExistsException       The user email already exists in the metadata database.
-     */
-    UserDto create(CreateUserDto data) throws UserExistsException, AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException, CredentialsInvalidException;
-
     /**
      * Deletes a user at the Authentication Service with given user id.
      *
@@ -35,31 +19,12 @@ public interface AuthenticationService {
      */
     void delete(User user) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException;
 
-    /**
-     * Finds a user with given username.
-     *
-     * @param username The username.
-     * @return The user, if successful.
-     * @throws AuthServiceException           The auth service responded with unexpected behavior.
-     * @throws AuthServiceConnectionException The connection with the auth service could not be established.
-     * @throws UserNotFoundException      The user was not found in the auth database.
-     */
-    UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException;
-
-    UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException;
-
-    TokenDto obtainToken(LoginRequestDto data) throws AuthServiceConnectionException, CredentialsInvalidException, AccountNotSetupException;
-
-    TokenDto refreshToken(String refreshToken) throws AuthServiceConnectionException, CredentialsInvalidException;
-
     /**
      * Updates the password of a user with given id.
      *
      * @param user The user.
      * @param data The new password.
-     * @throws AuthServiceException           The auth service responded with unexpected behavior.
-     * @throws AuthServiceConnectionException The connection with the auth service could not be established.
+     * @throws UserNotFoundException      The user was not found after creation in the auth database.
      */
-    void updatePassword(User user, UserPasswordDto data) throws AuthServiceException, AuthServiceConnectionException,
-            CredentialsInvalidException, UserNotFoundException;
+    void updatePassword(User user, UserPasswordDto data) throws UserNotFoundException;
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java
index c2f57c4e53af97573e7710b978f82b399ec54240..581641a93ab95927d63c5b4a5f6b069eb6f270b7 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java
@@ -4,7 +4,8 @@ import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.EmailExistsException;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
 import at.tuwien.exception.UserExistsException;
 import at.tuwien.exception.UserNotFoundException;
 
@@ -44,10 +45,9 @@ public interface UserService {
      * Creates a user in the metadata database managed by Keycloak in the given realm.
      *
      * @param data The user data.
-     * @param id   The user id.
      * @return The user, if successful.
      */
-    User create(CreateUserDto data, UUID id);
+    User create(CreateUserDto data) throws UserNotFoundException, AuthServiceException;
 
     /**
      * Updates the user information for a user with given id in the metadata database.
@@ -56,7 +56,7 @@ public interface UserService {
      * @param data The user information.
      * @return The user if successful. False otherwise.
      */
-    User modify(User user, UserUpdateDto data);
+    User modify(User user, UserUpdateDto data) throws UserNotFoundException, AuthServiceException;
 
     /**
      * Updates the user password for a user with given id in the metadata database.
@@ -74,13 +74,5 @@ public interface UserService {
      */
     void validateUsernameNotExists(String username) throws UserExistsException;
 
-    /**
-     * Validates if a user with the given email already exists in the metadata database.
-     *
-     * @param email The email.
-     * @throws EmailExistsException The user with this email already exists.
-     */
-    void validateEmailNotExists(String email) throws EmailExistsException;
-
     String getMariaDbPassword(String password);
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
index 24ebeb1665a77a874fd311f9e4fc4151ac80689f..1159913039ef59227758006f28d678db99329386 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
@@ -1,81 +1,36 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.auth.LoginRequestDto;
-import at.tuwien.api.auth.CreateUserDto;
-import at.tuwien.api.keycloak.TokenDto;
-import at.tuwien.api.keycloak.UserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.*;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.exception.CredentialsInvalidException;
+import at.tuwien.exception.UserNotFoundException;
 import at.tuwien.gateway.KeycloakGateway;
-import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.service.AuthenticationService;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.UUID;
-
 @Log4j2
 @Service
 public class AuthenticationServiceImpl implements AuthenticationService {
 
-    private final MetadataMapper metadataMapper;
     private final KeycloakGateway keycloakGateway;
 
     @Autowired
-    public AuthenticationServiceImpl(MetadataMapper metadataMapper, KeycloakGateway keycloakGateway) {
-        this.metadataMapper = metadataMapper;
+    public AuthenticationServiceImpl(KeycloakGateway keycloakGateway) {
         this.keycloakGateway = keycloakGateway;
     }
 
     @Override
-    public UserDto create(CreateUserDto data) throws UserExistsException, AuthServiceException,
-            AuthServiceConnectionException, EmailExistsException, CredentialsInvalidException {
-        keycloakGateway.createUser(metadataMapper.signupRequestDtoToUserCreateDto(data));
-        try {
-            return findByUsername(data.getUsername());
-        } catch (UserNotFoundException e) {
-            throw new AuthServiceException("Failed to find user in auth service", e);
-        }
-    }
-
-    @Override
-    public void delete(User user) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException,
-            CredentialsInvalidException {
-        final UserDto keycloakUser = findByUsername(user.getUsername());
-        keycloakGateway.deleteUser(keycloakUser.getId());
-    }
-
-    @Override
-    public UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException,
-            UserNotFoundException, CredentialsInvalidException {
-        return keycloakGateway.findByUsername(username);
-    }
-
-    @Override
-    public UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException,
-            CredentialsInvalidException {
-        return keycloakGateway.findById(id);
-    }
-
-    @Override
-    public TokenDto obtainToken(LoginRequestDto data) throws AuthServiceConnectionException,
-            CredentialsInvalidException, AccountNotSetupException {
-        return keycloakGateway.obtainUserToken(data.getUsername(), data.getPassword());
-    }
-
-    @Override
-    public TokenDto refreshToken(String refreshToken) throws AuthServiceConnectionException,
-            CredentialsInvalidException {
-        return keycloakGateway.refreshUserToken(refreshToken);
+    public void delete(User user) throws AuthServiceException, UserNotFoundException {
+        keycloakGateway.deleteUser(user.getKeycloakId());
     }
 
     @Override
-    public void updatePassword(User user, UserPasswordDto data) throws AuthServiceException,
-            AuthServiceConnectionException, CredentialsInvalidException, UserNotFoundException {
-        final UserDto keycloakUser = findByUsername(user.getUsername());
-        keycloakGateway.updateUserCredentials(keycloakUser.getId(), data);
+    public void updatePassword(User user, UserPasswordDto data) throws UserNotFoundException {
+        keycloakGateway.updateUserCredentials(user.getKeycloakId(), data);
     }
 
 }
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
index 17ba0bd60beba0281c605bfbf32e7439fc0a0fbc..8b4c73fb2f063cfc779fa001b7982675d74cf447 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java
@@ -216,6 +216,8 @@ public class DatabaseServiceImpl implements DatabaseService {
             }
             log.debug("fetched unknown table from data service: {}.{}", database.getInternalName(), table.getInternalName());
             final Table tableEntity = metadataMapper.tableDtoToTable(table);
+            tableEntity.setIsPublic(database.getIsPublic());
+            tableEntity.setIsSchemaPublic(database.getIsSchemaPublic());
             tableEntity.setDatabase(database);
             tableEntity.getColumns()
                     .forEach(column -> {
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
index 932a1a598c49f5f2a70f95b8c8264f5433a9cc13..96b8bd83963cca91e4731812ee0812a54a4630dc 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java
@@ -287,7 +287,7 @@ public class IdentifierServiceImpl implements IdentifierService {
         /* save identifier */
         switch (identifier.getType()) {
             case SUBSET -> {
-                log.debug("identifier type: subset with id {} and database with id {}", identifier.getQueryId(), identifier.getDatabase().getId());
+                log.debug("identifier type: subset with id {}", identifier.getQueryId());
                 final QueryDto query = dataServiceGateway.findQuery(identifier.getDatabase().getId(), identifier.getQueryId());
                 identifier.setQuery(query.getQuery());
                 identifier.setQueryId(query.getId());
@@ -298,14 +298,14 @@ public class IdentifierServiceImpl implements IdentifierService {
                 identifier.setResultHash(query.getResultHash());
             }
             case VIEW -> {
-                log.debug("identifier type: view with id {} and database with id {}", identifier.getViewId(), identifier.getDatabase().getId());
+                log.debug("identifier type: view with id {}", identifier.getViewId());
                 final View view = viewService.findById(identifier.getDatabase(), identifier.getViewId());
                 identifier.setViewId(view.getId());
                 identifier.setQuery(view.getQuery());
                 identifier.setQueryNormalized(view.getQuery());
                 identifier.setQueryHash(view.getQueryHash());
             }
-            case DATABASE -> log.debug("identifier type: database with id {}", identifier.getDatabase());
+            case DATABASE -> log.debug("identifier type: database with id {}", identifier.getDatabase().getId());
             case TABLE -> log.debug("identifier type: table with id {}", identifier.getTableId());
         }
         /* save identifier in metadata database */
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
index 042684f8c9e398aaf60ea8a15b6adb1b45b56df5..cb550be1a5d408139b656f0d0619467f8f59fa26 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
@@ -3,15 +3,18 @@ package at.tuwien.service.impl;
 import at.tuwien.api.auth.CreateUserDto;
 import at.tuwien.api.user.UserPasswordDto;
 import at.tuwien.api.user.UserUpdateDto;
-import at.tuwien.config.KeycloakConfig;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.EmailExistsException;
+import at.tuwien.exception.AuthServiceConnectionException;
+import at.tuwien.exception.AuthServiceException;
 import at.tuwien.exception.UserExistsException;
 import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.mapper.MetadataMapper;
 import at.tuwien.repository.UserRepository;
 import at.tuwien.service.UserService;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.RandomStringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -24,13 +27,16 @@ import java.util.UUID;
 @Service
 public class UserServiceImpl implements UserService {
 
-    private final KeycloakConfig keycloakConfig;
+    private final MetadataMapper metadataMapper;
     private final UserRepository userRepository;
+    private final KeycloakGateway keycloakGateway;
 
     @Autowired
-    public UserServiceImpl(KeycloakConfig keycloakConfig, UserRepository userRepository) {
-        this.keycloakConfig = keycloakConfig;
+    public UserServiceImpl(MetadataMapper metadataMapper, UserRepository userRepository,
+                           KeycloakGateway keycloakGateway) {
+        this.metadataMapper = metadataMapper;
         this.userRepository = userRepository;
+        this.keycloakGateway = keycloakGateway;
     }
 
     @Override
@@ -64,32 +70,36 @@ public class UserServiceImpl implements UserService {
     }
 
     @Override
-    public User create(CreateUserDto data, UUID id) {
+    public User create(CreateUserDto data) throws UserNotFoundException, AuthServiceException {
         /* create at authentication service */
         final User entity = User.builder()
-                .id(id)
+                .id(data.getLdapId())
+                .keycloakId(data.getId())
                 .username(data.getUsername())
-                .email(data.getEmail())
                 .theme("light")
-                .mariadbPassword(getMariaDbPassword(data.getPassword()))
+                .mariadbPassword(getMariaDbPassword(RandomStringUtils.randomAlphabetic(10))) /* user needs to set it later to access */
                 .language("en")
+                .firstname(data.getGivenName())
+                .lastname(data.getFamilyName())
                 .isInternal(false)
                 .build();
-        /* create at metadata database */
+        /* save in metadata database */
         final User user = userRepository.save(entity);
         log.info("Created user with id: {}", user.getId());
         return user;
     }
 
     @Override
-    public User modify(User user, UserUpdateDto data) {
+    public User modify(User user, UserUpdateDto data) throws UserNotFoundException, AuthServiceException {
         user.setFirstname(data.getFirstname());
         user.setLastname(data.getLastname());
         user.setAffiliation(data.getAffiliation());
         user.setOrcid(data.getOrcid());
         user.setTheme(data.getTheme());
         user.setLanguage(data.getLanguage());
-        /* create at metadata database */
+        /* save in auth service */
+        keycloakGateway.updateUser(user.getKeycloakId(), data);
+        /* save in metadata database */
         user = userRepository.save(user);
         log.info("Modified user with id: {}", user.getId());
         return user;
@@ -110,13 +120,6 @@ public class UserServiceImpl implements UserService {
         }
     }
 
-    @Override
-    public void validateEmailNotExists(String email) throws EmailExistsException {
-        if (userRepository.existsByEmail(email)) {
-            throw new EmailExistsException("User with email " + email + " already exists");
-        }
-    }
-
     @Override
     public String getMariaDbPassword(String password) {
         final byte[] utf8 = password.getBytes(StandardCharsets.UTF_8);
diff --git a/dbrepo-metadata-service/test/pom.xml b/dbrepo-metadata-service/test/pom.xml
index 97768ad4a7d4fa6d467be813af71d9e6ee82ed5d..d51ed22d4d84941f982296b18b4fcb9005db7dce 100644
--- a/dbrepo-metadata-service/test/pom.xml
+++ b/dbrepo-metadata-service/test/pom.xml
@@ -6,12 +6,12 @@
     <parent>
         <groupId>at.tuwien</groupId>
         <artifactId>dbrepo-metadata-service</artifactId>
-        <version>1.6.2</version>
+        <version>1.6.3</version>
     </parent>
 
     <artifactId>dbrepo-metadata-service-test</artifactId>
     <name>dbrepo-metadata-service-test</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <dependencies>
         <dependency>
diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
index f4b89de5852dc4008d365835a5e29ccd1db7231c..0f07af9af968eae4e16f1f54a099312a20cabbb0 100644
--- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
+++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
@@ -46,7 +46,6 @@ import at.tuwien.api.orcid.person.name.OrcidNameDto;
 import at.tuwien.api.orcid.person.name.OrcidValueDto;
 import at.tuwien.api.semantics.*;
 import at.tuwien.api.user.UserAttributesDto;
-import at.tuwien.api.user.UserDto;
 import at.tuwien.api.user.*;
 import at.tuwien.api.user.internal.UpdateUserPasswordDto;
 import at.tuwien.entities.container.Container;
@@ -99,12 +98,12 @@ import static java.time.temporal.ChronoUnit.MINUTES;
  * <ul>
  * <li>Table 1 (Private Data, Private Schema)</li>
  * <li>Table 2 (Private Data, Public Schema)</li>
- * <li>Table 3</li>
- * <li>Table 4</li>
+ * <li>Table 3 (Private Data, Private Schema)</li>
+ * <li>Table 4 (Public Data, Private Schema)</li>
  * <li>Query 1</li>
- * <li>View 1</li>
- * <li>View 2</li>
- * <li>View 3</li>
+ * <li>View 1 (Private Data, Private Schema)</li>
+ * <li>View 2 (Public Data, Public Schema)</li>
+ * <li>View 3 (Public Data, Private Schema)</li>
  * <li>Identifier 1 (Title=en, Description=en, type=database)</li>
  * <li>Identifier 2 (Title=en, Description=en, type=subset, queryId=1)</li>
  * <li>Identifier 3 (Title=en, Description=en, type=view, viewId=1)</li>
@@ -113,22 +112,22 @@ import static java.time.temporal.ChronoUnit.MINUTES;
  * <p>
  * Database 2 (Private Data, Public Schema, User 2) -> Container 1
  * <ul>
- * <li>Table 5</li>
- * <li>Table 6</li>
- * <li>Table 7</li>
+ * <li>Table 5 (Public Data, Public Schema)</li>
+ * <li>Table 6 (Public Data, Private Schema)</li>
+ * <li>Table 7 (Public Data, Public Schema)</li>
  * <li>Query 2</li>
  * <li>Query 6</li>
- * <li>View 4</li>
+ * <li>View 4 (Public Data, Private Schema)</li>
  * <li>Identifier 5 (Title=de, Description=de)</li>
  * </ul>
  * <p>
  * Database 3 (Public Data, Private Schema, User 3) -> Container 1
  * <ul>
- * <li>Table 8</li>
+ * <li>Table 8 (Private Data, Private Schema)</li>
  * <li>Query 3</li>
  * <li>Query 4</li>
  * <li>Query 5</li>
- * <li>View 5</li>
+ * <li>View 5 (Public Data, Public Schema)</li>
  * <li>Identifier 6 (Title=en, Description=en, Query=3)</li>
  * </ul>
  * <p>
@@ -153,7 +152,7 @@ public abstract class BaseTest {
 
     public final static String RABBITMQ_IMAGE = "rabbitmq:3.13.7";
 
-    public final static String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:24.0";
+    public final static String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:26.0";
 
     public final static String[] DEFAULT_SEMANTICS_HANDLING = new String[]{"default-semantics-handling",
             "create-semantic-unit", "execute-semantic-query", "table-semantic-analyse", "create-semantic-concept"};
@@ -166,7 +165,7 @@ public abstract class BaseTest {
             "update-semantic-unit", "create-ontology", "update-ontology"};
 
     public final static String[] DEFAULT_CONTAINER_HANDLING = new String[]{"default-container-handling",
-            "create-container", "list-containers", "modify-container-state", "find-container"};
+            "create-container", "list-containers", "modify-container-state"};
 
     public final static String[] ESCALATED_CONTAINER_HANDLING = new String[]{"escalated-container-handling",
             "modify-foreign-container-state", "delete-container"};
@@ -186,9 +185,9 @@ public abstract class BaseTest {
             "modify-identifier-metadata", "update-foreign-identifier", "create-foreign-identifier"};
 
     public final static String[] DEFAULT_QUERY_HANDLING = new String[]{"default-query-handling", "view-table-data",
-            "execute-query", "view-table-history", "list-database-views", "view-database-view-data",
-            "export-query-data", "create-database-view", "delete-database-view", "delete-table-data",
-            "export-table-data", "persist-query", "re-execute-query", "insert-table-data", "find-database-view"};
+            "execute-query", "view-table-history", "list-database-views", "export-query-data", "create-database-view",
+            "delete-database-view", "delete-table-data", "export-table-data", "persist-query", "re-execute-query",
+            "insert-table-data", "find-database-view"};
 
     public final static String[] ESCALATED_QUERY_HANDLING = new String[]{"escalated-query-handling"};
 
@@ -217,7 +216,7 @@ public abstract class BaseTest {
     public final static String[] DEFAULT_DATA_STEWARD_ROLES = ArrayUtils.merge(List.of(new String[]{"default-data-steward-roles"},
             ESCALATED_IDENTIFIER_HANDLING, DEFAULT_SEMANTICS_HANDLING, ESCALATED_SEMANTICS_HANDLING, DEFAULT_VIEW_HANDLING));
 
-    public final static String[] DEFAULT_LOCAL_ADMIN_ROLES = new String[]{"admin"};
+    public final static String[] DEFAULT_LOCAL_ADMIN_ROLES = new String[]{"system"};
 
     public final static List<GrantedAuthorityDto> AUTHORITY_LOCAL_ADMIN_ROLES = Arrays.stream(DEFAULT_LOCAL_ADMIN_ROLES)
             .map(GrantedAuthorityDto::new)
@@ -440,13 +439,13 @@ public abstract class BaseTest {
     public final static String USER_BROKER_PASSWORD = "guest";
 
     public final static UUID USER_LOCAL_ADMIN_ID = UUID.fromString("a54dcb2e-a644-4e82-87e7-05a96413983d");
+    public final static UUID USER_LOCAL_ADMIN_KEYCLOAK_ID = UUID.fromString("703c2ca0-8fc3-4c03-9bc5-4dae6b211e78");
     public final static String USER_LOCAL_ADMIN_USERNAME = "admin";
     @SuppressWarnings("java:S2068")
     public final static String USER_LOCAL_ADMIN_PASSWORD = "admin";
     public final static String USER_LOCAL_ADMIN_THEME = "dark";
     public final static Boolean USER_LOCAL_ADMIN_IS_INTERNAL = true;
     public final static Boolean USER_LOCAL_ADMIN_ENABLED = true;
-    public final static String USER_LOCAL_ADMIN_EMAIL = "admin@local";
     @SuppressWarnings("java:S2068")
     public final static String USER_LOCAL_ADMIN_MARIADB_PASSWORD = "*440BA4FD1A87A0999647DB67C0EE258198B247BA";
 
@@ -456,7 +455,7 @@ public abstract class BaseTest {
             .build();
 
     public final static UserDetails USER_LOCAL_ADMIN_DETAILS = UserDetailsDto.builder()
-            .id(String.valueOf(USER_LOCAL_ADMIN_ID))
+            .id(USER_LOCAL_ADMIN_ID.toString())
             .username(USER_LOCAL_ADMIN_USERNAME)
             .password(USER_LOCAL_ADMIN_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_LOCAL_ADMIN_AUTHORITIES)
@@ -464,8 +463,8 @@ public abstract class BaseTest {
 
     public final static User USER_LOCAL = User.builder()
             .id(USER_LOCAL_ADMIN_ID)
+            .keycloakId(USER_LOCAL_ADMIN_KEYCLOAK_ID)
             .username(USER_LOCAL_ADMIN_USERNAME)
-            .email(USER_LOCAL_ADMIN_EMAIL)
             .mariadbPassword(USER_LOCAL_ADMIN_MARIADB_PASSWORD)
             .theme(USER_LOCAL_ADMIN_THEME)
             .isInternal(USER_LOCAL_ADMIN_IS_INTERNAL)
@@ -475,8 +474,7 @@ public abstract class BaseTest {
             USER_LOCAL_ADMIN_PASSWORD, USER_LOCAL_ADMIN_DETAILS.getAuthorities());
 
     public final static UUID USER_1_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b");
-    public final static UUID USER_1_LDAP_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b");
-    public final static String USER_1_EMAIL = "john.doe@example.com";
+    public final static UUID USER_1_KEYCLOAK_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b");
     public final static String USER_1_USERNAME = "junit1";
     @SuppressWarnings("java:S2068")
     public final static String USER_1_PASSWORD = "junit1";
@@ -530,7 +528,6 @@ public abstract class BaseTest {
 
     public final static UserCreateDto USER_1_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder()
             .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
             .enabled(USER_1_ENABLED)
             .credentials(new LinkedList<>(List.of(USER_1_KEYCLOAK_CREDENTIAL_1)))
             .attributes(UserCreateAttributesDto.builder()
@@ -540,7 +537,6 @@ public abstract class BaseTest {
 
     public final static UserCreateDto USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder()
             .username(USER_LOCAL_ADMIN_USERNAME)
-            .email(USER_LOCAL_ADMIN_EMAIL)
             .enabled(USER_LOCAL_ADMIN_ENABLED)
             .credentials(new LinkedList<>(List.of(USER_LOCAL_KEYCLOAK_CREDENTIAL_1)))
             .groups(new LinkedList<>(List.of("system")))
@@ -551,8 +547,8 @@ public abstract class BaseTest {
 
     public final static User USER_1 = User.builder()
             .id(USER_1_ID)
+            .keycloakId(USER_1_KEYCLOAK_ID)
             .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
             .firstname(USER_1_FIRSTNAME)
             .lastname(USER_1_LASTNAME)
             .affiliation(USER_1_AFFILIATION)
@@ -586,19 +582,6 @@ public abstract class BaseTest {
             .password(USER_1_PASSWORD)
             .build();
 
-    public final static at.tuwien.api.keycloak.UserDto USER_1_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder()
-            .id(USER_1_ID)
-            .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
-            .emailVerified(USER_1_VERIFIED)
-            .notBefore(USER_1_NOT_BEFORE)
-            .totp(USER_1_TOTP)
-            .attributes(at.tuwien.api.keycloak.UserAttributesDto.builder()
-                    .ldapEntryDn(new String[]{"cn=" + USER_1_USERNAME + ",dn=dbrepo,dn=at"})
-                    .ldapId(new UUID[]{USER_1_LDAP_ID})
-                    .build())
-            .build();
-
     public final static UserBriefDto USER_1_BRIEF_DTO = UserBriefDto.builder()
             .id(USER_1_ID)
             .username(USER_1_USERNAME)
@@ -612,7 +595,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_1_DETAILS = UserDetailsDto.builder()
             .id(USER_1_ID.toString())
             .username(USER_1_USERNAME)
-            .email(USER_1_EMAIL)
             .password(USER_1_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
@@ -621,9 +603,9 @@ public abstract class BaseTest {
             USER_1_PASSWORD, USER_1_DETAILS.getAuthorities());
 
     public final static CreateUserDto USER_1_SIGNUP_REQUEST_DTO = CreateUserDto.builder()
+            .id(USER_1_KEYCLOAK_ID)
+            .ldapId(USER_1_ID)
             .username(USER_1_USERNAME)
-            .password(USER_1_PASSWORD)
-            .email(USER_1_EMAIL)
             .build();
 
     public final static LoginRequestDto USER_1_LOGIN_REQUEST_DTO = LoginRequestDto.builder()
@@ -632,7 +614,7 @@ public abstract class BaseTest {
             .build();
 
     public final static UUID USER_2_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c");
-    public final static UUID USER_2_LDAP_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c");
+    public final static UUID USER_2_KEYCLOAK_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c");
     public final static String USER_2_EMAIL = "jane.doe@example.com";
     public final static String USER_2_USERNAME = "junit2";
     public final static String USER_2_FIRSTNAME = "Jane";
@@ -666,8 +648,8 @@ public abstract class BaseTest {
 
     public final static User USER_2 = User.builder()
             .id(USER_2_ID)
+            .keycloakId(USER_2_KEYCLOAK_ID)
             .username(USER_2_USERNAME)
-            .email(USER_2_EMAIL)
             .firstname(USER_2_FIRSTNAME)
             .lastname(USER_2_LASTNAME)
             .affiliation(USER_2_AFFILIATION)
@@ -699,28 +681,21 @@ public abstract class BaseTest {
             .build();
 
     public final static CreateUserDto USER_2_SIGNUP_REQUEST_DTO = CreateUserDto.builder()
+            .id(USER_2_KEYCLOAK_ID)
+            .ldapId(USER_2_ID)
             .username(USER_2_USERNAME)
-            .password(USER_2_PASSWORD)
             .email(USER_2_EMAIL)
+            .givenName(USER_2_FIRSTNAME)
+            .familyName(USER_2_LASTNAME)
             .build();
 
     public final static UserDetails USER_2_DETAILS = UserDetailsDto.builder()
             .id(USER_2_ID.toString())
             .username(USER_2_USERNAME)
-            .email(USER_2_EMAIL)
             .password(USER_2_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
 
-    public final static at.tuwien.api.keycloak.UserDto USER_2_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder()
-            .id(USER_2_ID)
-            .username(USER_2_USERNAME)
-            .email(USER_2_EMAIL)
-            .emailVerified(USER_2_VERIFIED)
-            .notBefore(USER_2_NOT_BEFORE)
-            .totp(USER_2_TOTP)
-            .build();
-
     public final static at.tuwien.api.amqp.UserDetailsDto USER_2_DETAILS_DTO = at.tuwien.api.amqp.UserDetailsDto.builder()
             .name(USER_2_USERNAME)
             .tags(new String[]{})
@@ -730,7 +705,7 @@ public abstract class BaseTest {
             USER_2_PASSWORD, USER_2_DETAILS.getAuthorities());
 
     public final static UUID USER_3_ID = UUID.fromString("7b080e33-d8db-4276-9d53-47208e657006");
-    public final static UUID USER_3_LDAP_ID = UUID.fromString("7b080e33-d8db-4276-9d53-47208e657006");
+    public final static UUID USER_3_KEYCLOAK_ID = UUID.fromString("b0108bc3-95aa-4a3f-8868-dc301286aeca");
     public final static String USER_3_USERNAME = "junit3";
     public final static String USER_3_FIRSTNAME = "System";
     public final static String USER_3_LASTNAME = "System";
@@ -762,8 +737,8 @@ public abstract class BaseTest {
 
     public final static User USER_3 = User.builder()
             .id(USER_3_ID)
+            .keycloakId(USER_3_KEYCLOAK_ID)
             .username(USER_3_USERNAME)
-            .email(USER_3_EMAIL)
             .firstname(USER_3_FIRSTNAME)
             .lastname(USER_3_LASTNAME)
             .affiliation(USER_3_AFFILIATION)
@@ -795,18 +770,14 @@ public abstract class BaseTest {
     public final static UserDetails USER_3_DETAILS = UserDetailsDto.builder()
             .id(USER_3_ID.toString())
             .username(USER_3_USERNAME)
-            .email(USER_3_EMAIL)
             .password(USER_3_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
 
-    public final static at.tuwien.api.keycloak.UserDto USER_3_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder()
-            .id(USER_3_ID)
+    public final static CreateUserDto USER_3_SIGNUP_REQUEST_DTO = CreateUserDto.builder()
+            .id(USER_3_KEYCLOAK_ID)
+            .ldapId(USER_3_ID)
             .username(USER_3_USERNAME)
-            .email(USER_3_EMAIL)
-            .emailVerified(USER_3_VERIFIED)
-            .notBefore(USER_3_NOT_BEFORE)
-            .totp(USER_3_TOTP)
             .build();
 
     public final static Principal USER_3_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_3_DETAILS,
@@ -818,7 +789,7 @@ public abstract class BaseTest {
             .build();
 
     public final static UUID USER_4_ID = UUID.fromString("791d58c5-bfab-4520-b4fc-b44d4ab9feb0");
-    public final static UUID USER_4_LDAP_ID = UUID.fromString("791d58c5-bfab-4520-b4fc-b44d4ab9feb0");
+    public final static UUID USER_4_KEYCLOAK_ID = UUID.fromString("25040ad3-6d57-4052-b357-6b4c8a6e7f4d");
     public final static String USER_4_USERNAME = "junit4";
     public final static String USER_4_FIRSTNAME = "JUnit";
     public final static String USER_4_LASTNAME = "4";
@@ -830,7 +801,6 @@ public abstract class BaseTest {
     @SuppressWarnings("java:S2068")
     public final static String USER_4_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit4 */;
     public final static String USER_4_QUALIFIED_NAME = USER_4_FIRSTNAME + " " + USER_4_LASTNAME + " — @" + USER_4_USERNAME;
-    public final static String USER_4_EMAIL = "junit4@ossdip.at";
     public final static Boolean USER_4_VERIFIED = true;
     public final static Boolean USER_4_ENABLED = true;
     public final static Boolean USER_4_IS_INTERNAL = false;
@@ -847,8 +817,8 @@ public abstract class BaseTest {
 
     public final static User USER_4 = User.builder()
             .id(USER_4_ID)
+            .keycloakId(USER_4_KEYCLOAK_ID)
             .username(USER_4_USERNAME)
-            .email(USER_4_EMAIL)
             .firstname(USER_4_FIRSTNAME)
             .lastname(USER_4_LASTNAME)
             .affiliation(USER_4_AFFILIATION)
@@ -880,7 +850,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_4_DETAILS = UserDetailsDto.builder()
             .id(USER_4_ID.toString())
             .username(USER_4_USERNAME)
-            .email(USER_4_EMAIL)
             .password(USER_4_PASSWORD)
             .authorities(new LinkedList<>())
             .build();
@@ -889,7 +858,7 @@ public abstract class BaseTest {
             USER_4_PASSWORD, USER_4_DETAILS.getAuthorities());
 
     public final static UUID USER_5_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630");
-    public final static UUID USER_5_LDAP_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630");
+    public final static UUID USER_5_KEYCLOAK_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630");
     public final static String USER_5_USERNAME = "nobody";
     public final static String USER_5_FIRSTNAME = "No";
     public final static String USER_5_LASTNAME = "Body";
@@ -901,7 +870,6 @@ public abstract class BaseTest {
     @SuppressWarnings("java:S2068")
     public final static String USER_5_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */;
     public final static String USER_5_QUALIFIED_NAME = USER_5_FIRSTNAME + " " + USER_5_LASTNAME + " — @" + USER_5_USERNAME;
-    public final static String USER_5_EMAIL = "system@ossdip.at";
     public final static Boolean USER_5_VERIFIED = true;
     public final static Boolean USER_5_ENABLED = true;
     public final static Boolean USER_5_IS_INTERNAL = false;
@@ -936,7 +904,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_5_DETAILS = UserDetailsDto.builder()
             .id(USER_5_ID.toString())
             .username(USER_5_USERNAME)
-            .email(USER_5_EMAIL)
             .password(USER_5_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES)
             .build();
@@ -946,8 +913,8 @@ public abstract class BaseTest {
 
     public final static User USER_5 = User.builder()
             .id(USER_5_ID)
+            .keycloakId(USER_5_KEYCLOAK_ID)
             .username(USER_5_USERNAME)
-            .email(USER_5_EMAIL)
             .firstname(USER_5_FIRSTNAME)
             .lastname(USER_5_LASTNAME)
             .affiliation(USER_5_AFFILIATION)
@@ -967,7 +934,6 @@ public abstract class BaseTest {
     public final static String USER_6_PASSWORD = "junit5";
     @SuppressWarnings("java:S2068")
     public final static String USER_6_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */;
-    public final static String USER_6_EMAIL = "system@ossdip.at";
     public final static Boolean USER_6_VERIFIED = true;
     public final static Boolean USER_6_ENABLED = true;
     public final static Boolean USER_6_IS_INTERNAL = false;
@@ -985,7 +951,6 @@ public abstract class BaseTest {
     public final static UserDetails USER_6_DETAILS = UserDetailsDto.builder()
             .id(USER_6_ID.toString())
             .username(USER_6_USERNAME)
-            .email(USER_6_EMAIL)
             .password(USER_6_PASSWORD)
             .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES)
             .build();
@@ -2067,7 +2032,7 @@ public abstract class BaseTest {
     public final static String TABLE_6_INTERNALNAME = "names";
     public final static Boolean TABLE_6_VERSIONED = true;
     public final static Boolean TABLE_6_IS_PUBLIC = true;
-    public final static Boolean TABLE_6_SCHEMA_PUBLIC = true;
+    public final static Boolean TABLE_6_SCHEMA_PUBLIC = false;
     public final static Boolean TABLE_6_PROCESSED_CONSTRAINTS = true;
     public final static String TABLE_6_DESCRIPTION = "Some names dataset";
     public final static String TABLE_6_QUEUE_NAME = TABLE_6_INTERNALNAME;
@@ -2186,9 +2151,8 @@ public abstract class BaseTest {
     public final static String TABLE_4_NAME = "Sensor 2";
     public final static String TABLE_4_INTERNALNAME = "sensor_2";
     public final static Boolean TABLE_4_VERSIONED = true;
-    public final static Boolean TABLE_4_IS_PUBLIC = false;
+    public final static Boolean TABLE_4_IS_PUBLIC = true;
     public final static Boolean TABLE_4_SCHEMA_PUBLIC = false;
-    public final static Boolean TABLE_4_PROCESSED_CONSTRAINTS = true;
     public final static String TABLE_4_DESCRIPTION = "Hello sensor";
     public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNALNAME;
     public final static String TABLE_4_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_4_ID;
@@ -2366,7 +2330,6 @@ public abstract class BaseTest {
     public final static Boolean TABLE_8_VERSIONED = true;
     public final static Boolean TABLE_8_IS_PUBLIC = false;
     public final static Boolean TABLE_8_SCHEMA_PUBLIC = false;
-    public final static Boolean TABLE_8_PROCESSED_CONSTRAINTS = true;
     public final static String TABLE_8_DESCRIPTION = "Hello mfcc";
     public final static String TABLE_8_QUEUE_NAME = TABLE_8_INTERNAL_NAME;
     public final static String TABLE_8_ROUTING_KEY = "dbrepo\\." + DATABASE_3_ID + "\\." + TABLE_8_ID;
@@ -5071,8 +5034,8 @@ public abstract class BaseTest {
     public final static String VIEW_1_INTERNAL_NAME = "junit";
     public final static Long VIEW_1_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long VIEW_1_DATABASE_ID = DATABASE_1_ID;
-    public final static Boolean VIEW_1_PUBLIC = true;
-    public final static Boolean VIEW_1_SCHEMA_PUBLIC = true;
+    public final static Boolean VIEW_1_PUBLIC = false;
+    public final static Boolean VIEW_1_SCHEMA_PUBLIC = false;
     public final static String VIEW_1_QUERY = "select `location`, `lat`, `lng` from `weather_location`";
     public final static String VIEW_1_QUERY_HASH = "dc81a6877c7c51a6a6f406e1fc2a255e44a0d49a20548596e0d583c3eb849c23";
 
@@ -5393,7 +5356,7 @@ public abstract class BaseTest {
     public final static String VIEW_3_INTERNAL_NAME = "junit3";
     public final static Long VIEW_3_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long VIEW_3_DATABASE_ID = DATABASE_1_ID;
-    public final static Boolean VIEW_3_PUBLIC = false;
+    public final static Boolean VIEW_3_PUBLIC = true;
     public final static Boolean VIEW_3_SCHEMA_PUBLIC = false;
     public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`date` from `weather_aus` w join `junit2` m on m.`location` = w.`location` and m.`date` = w.`date`";
     public final static String VIEW_3_QUERY_HASH = "bbbaa56a5206b3dc3e6cf9301b0db9344eb6f19b100c7b88550ffb597a0bd255";
@@ -5555,7 +5518,7 @@ public abstract class BaseTest {
     public final static Long VIEW_4_TABLE_ID = TABLE_5_ID;
     public final static Table VIEW_4_TABLE = TABLE_5;
     public final static Boolean VIEW_4_PUBLIC = true;
-    public final static Boolean VIEW_4_SCHEMA_PUBLIC = true;
+    public final static Boolean VIEW_4_SCHEMA_PUBLIC = false;
     public final static String VIEW_4_QUERY = "SELECT `animal_name`, `hair`, `feathers`, `eggs`, `milk`, `airborne`, `aquatic`, `predator`, `backbone`, `breathes`, `venomous`, `fins`, `legs`, `tail`, `domestic`, `catsize`, `class_type` FROM `zoo` WHERE `class_type` = 1";
     public final static String VIEW_4_QUERY_HASH = "3561cd0bb0b0e94d6f15ae602134252a5760d09d660a71a4fb015b6991c8ba0b";
 
diff --git a/dbrepo-search-service/Pipfile b/dbrepo-search-service/Pipfile
index f7161287a02cd23f2d18444f04d896b3351c3068..3ae299480180796fb640802d582aaf2745f876ca 100644
--- a/dbrepo-search-service/Pipfile
+++ b/dbrepo-search-service/Pipfile
@@ -18,7 +18,7 @@ jwt = "~=1.3"
 testcontainers-opensearch = "*"
 pytest = "*"
 rdflib = "*"
-dbrepo = {path = "./lib/dbrepo-1.6.2.tar.gz"}
+dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"}
 gunicorn = "*"
 
 [dev-packages]
diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock
index d75a0069a1a39cd64ff953624e9bbb8adb61c78a..6c62e03b928bcd62b443395c39dcdef902fe488d 100644
--- a/dbrepo-search-service/Pipfile.lock
+++ b/dbrepo-search-service/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "729017f537f9f8fb6dcc15703392c7fd79aec494feba4c107e7a1888e8ea955d"
+            "sha256": "2ff9fc673f1fb1e5dc272aa711f4e730088fa0188b44449db042abf99b6c4db7"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -124,11 +124,11 @@
         },
         "attrs": {
             "hashes": [
-                "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff",
-                "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"
+                "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e",
+                "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==24.3.0"
+            "version": "==25.1.0"
         },
         "blinker": {
             "hashes": [
@@ -360,9 +360,9 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:a41ca60353510cbecf8fb647cf2483acb100258743794a16bc8ad6f8e9ea4481"
+                "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d"
             ],
-            "path": "./lib/dbrepo-1.6.2.tar.gz"
+            "path": "./lib/dbrepo-1.6.3.tar.gz"
         },
         "docker": {
             "hashes": [
@@ -739,11 +739,11 @@
         },
         "mistune": {
             "hashes": [
-                "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1",
-                "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667"
+                "sha256:02106ac2aa4f66e769debbfa028509a275069dcffce0dfa578edd7b991ee700a",
+                "sha256:e0740d635f515119f7d1feb6f9b192ee60f0cc649f80a8f944f905706a21654c"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==3.1.0"
+            "version": "==3.1.1"
         },
         "multidict": {
             "hashes": [
@@ -1099,11 +1099,11 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff",
-                "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"
+                "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584",
+                "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.10.5"
+            "version": "==2.10.6"
         },
         "pydantic-core": {
             "hashes": [
@@ -1330,11 +1330,11 @@
         },
         "referencing": {
             "hashes": [
-                "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794",
-                "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade"
+                "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa",
+                "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"
             ],
             "markers": "python_version >= '3.9'",
-            "version": "==0.36.1"
+            "version": "==0.36.2"
         },
         "requests": {
             "hashes": [
diff --git a/dbrepo-search-service/init/Pipfile b/dbrepo-search-service/init/Pipfile
index 8ded635ab78a63a71e36787a2a91f48f61932b4c..b74ed7bc40da1da1c51c401b53a1da2676fb739e 100644
--- a/dbrepo-search-service/init/Pipfile
+++ b/dbrepo-search-service/init/Pipfile
@@ -9,7 +9,7 @@ opensearch-py = "~=2.2"
 python-dotenv = "~=1.0"
 testcontainers-opensearch = "*"
 pytest = "*"
-dbrepo = {path = "./lib/dbrepo-1.6.2.tar.gz"}
+dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"}
 rdflib = "*"
 
 [dev-packages]
diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock
index e4a2e7d71877f6d44a929b2e344390bbf1117db0..039873e7c5ffd4b2e5c6352027f7f501254ce5c6 100644
--- a/dbrepo-search-service/init/Pipfile.lock
+++ b/dbrepo-search-service/init/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "39898ff53a7a701c750b2fc2bfe2d7f72704100e41a183feceb1d8bd09c71a00"
+            "sha256": "dac534d1eb6a0942c0e296c8a58491847c65d3ca23315039a3725591c86f694f"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -124,11 +124,11 @@
         },
         "attrs": {
             "hashes": [
-                "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff",
-                "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"
+                "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e",
+                "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==24.3.0"
+            "version": "==25.1.0"
         },
         "blinker": {
             "hashes": [
@@ -254,9 +254,9 @@
         },
         "dbrepo": {
             "hashes": [
-                "sha256:a41ca60353510cbecf8fb647cf2483acb100258743794a16bc8ad6f8e9ea4481"
+                "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d"
             ],
-            "path": "./lib/dbrepo-1.6.2.tar.gz"
+            "path": "./lib/dbrepo-1.6.3.tar.gz"
         },
         "docker": {
             "hashes": [
@@ -808,11 +808,11 @@
         },
         "pydantic": {
             "hashes": [
-                "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff",
-                "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"
+                "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584",
+                "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"
             ],
             "markers": "python_version >= '3.8'",
-            "version": "==2.10.5"
+            "version": "==2.10.6"
         },
         "pydantic-core": {
             "hashes": [
diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1
Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl differ
diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253
Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz differ
diff --git a/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1
Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl differ
diff --git a/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253
Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz differ
diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py
index 9da77adfde53e155dddc36f364bea9d974964125..edbdff683dff0f66319d87fb064fdeab6931bca0 100644
--- a/dbrepo-search-service/test/test_opensearch_client.py
+++ b/dbrepo-search-service/test/test_opensearch_client.py
@@ -2,7 +2,7 @@ import unittest
 
 import opensearchpy
 from dbrepo.api.dto import Database, Table, Column, ColumnType, Constraints, PrimaryKey, \
-    TableMinimal, ColumnMinimal, ConceptBrief, UnitBrief, UserBrief, ContainerBrief, ImageBrief
+    ConceptBrief, UnitBrief, UserBrief, ContainerBrief, ImageBrief, TableBrief, ColumnBrief
 from opensearchpy import NotFoundError
 
 from app import app
@@ -57,10 +57,6 @@ class OpenSearchClientTest(unittest.TestCase):
 
     def test_update_database_succeeds(self):
         with app.app_context():
-            # mock
-            OpenSearchClient().update_database(database_id=req.id, data=req)
-
-            # test
             req.tables = [Table(id=1,
                                 name="Test Table",
                                 internal_name="test_table",
@@ -71,10 +67,20 @@ class OpenSearchClientTest(unittest.TestCase):
                                 database_id=req.id,
                                 constraints=Constraints(uniques=[], foreign_keys=[], checks=[],
                                                         primary_key=[PrimaryKey(id=1,
-                                                                                table=TableMinimal(id=1,
-                                                                                                   database_id=req.id),
-                                                                                column=ColumnMinimal(id=1, table_id=1,
-                                                                                                     database_id=req.id))]),
+                                                                                table=TableBrief(id=1,
+                                                                                                 database_id=req.id,
+                                                                                                 name="Test Table",
+                                                                                                 internal_name="test_table",
+                                                                                                 is_public=True,
+                                                                                                 is_schema_public=True,
+                                                                                                 is_versioned=True,
+                                                                                                 owned_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502"),
+                                                                                column=ColumnBrief(id=1,
+                                                                                                   name="ID",
+                                                                                                   database_id=req.id,
+                                                                                                   table_id=1,
+                                                                                                   internal_name="id",
+                                                                                                   type=ColumnType.BIGINT))]),
                                 is_versioned=True,
                                 owner=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"),
                                 columns=[Column(id=1,
@@ -85,6 +91,10 @@ class OpenSearchClientTest(unittest.TestCase):
                                                 internal_name="id",
                                                 type=ColumnType.BIGINT,
                                                 is_null_allowed=False)])]
+            # mock
+            OpenSearchClient().update_database(database_id=req.id, data=req)
+
+            # test
             database = OpenSearchClient().update_database(database_id=req.id, data=req)
             self.assertEqual(1, database.id)
             self.assertEqual("Test", database.name)
diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb
index 45a8c51c621dab127458d68a4493b23d2df9f88d..7ee1d3897245ee94212d8bfb6a6b97556b64f1d2 100755
Binary files a/dbrepo-ui/bun.lockb and b/dbrepo-ui/bun.lockb differ
diff --git a/dbrepo-ui/components/JumboBox.vue b/dbrepo-ui/components/JumboBox.vue
index d2b804f819f22782ba4895c601c8b2ea118ce4e3..5a26ec6139bff1a1b816c2acce1dc3fb08cd7207 100644
--- a/dbrepo-ui/components/JumboBox.vue
+++ b/dbrepo-ui/components/JumboBox.vue
@@ -21,6 +21,7 @@
     </v-row>
   </div>
 </template>
+
 <script>
 export default {
   props: {
diff --git a/dbrepo-ui/components/Loading.vue b/dbrepo-ui/components/Loading.vue
index 743701ab6724dba40d6baa0cb0cfafcb26061556..84094bfef8773aa306d977e6f0f7cbb4cca1dde9 100644
--- a/dbrepo-ui/components/Loading.vue
+++ b/dbrepo-ui/components/Loading.vue
@@ -7,6 +7,7 @@
       indeterminate />
   </v-list-item-title>
 </template>
+
 <script>
 export default {
   props: {
diff --git a/dbrepo-ui/components/OntologiesList.vue b/dbrepo-ui/components/OntologiesList.vue
deleted file mode 100644
index c7120cac4a1e58e4a1f22c651f77aebcaf002584..0000000000000000000000000000000000000000
--- a/dbrepo-ui/components/OntologiesList.vue
+++ /dev/null
@@ -1,73 +0,0 @@
-<template>
-  <div>
-    <v-card
-      v-for="(ontology, idx) in ontologies"
-      :key="idx"
-      :to="`/semantic/ontology/${ontology.id}`"
-      variant="flat"
-      rounded="0">
-      <v-divider
-        class="mx-4" />
-      <v-card-title>
-        {{ ontology.prefix }}
-      </v-card-title>
-      <v-card-subtitle>
-        {{ ontology.uri }}
-      </v-card-subtitle>
-      <v-card-text>
-        <div
-          class="db-tags">
-          <v-chip
-            v-if="ontology.sparql"
-            size="small"
-            color="success"
-            text="SPARQL"
-            variant="outlined" />
-          <v-chip
-            v-if="ontology.rdf"
-            size="small"
-            text="RDF"
-            variant="outlined" />
-        </div>
-      </v-card-text>
-    </v-card>
-  </div>
-</template>
-
-<script>
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  data () {
-    return {
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    }
-  },
-  mounted () {
-  },
-  methods: {
-  }
-}
-</script>
-
-<style>
-.db-tags .v-chip:not(:first-child) {
-  margin-left: 4px;
-}
-</style>
diff --git a/dbrepo-ui/components/ResourceStatus.vue b/dbrepo-ui/components/ResourceStatus.vue
index 5167d899ea6e73c150db478f8fc3b063a3ba1e12..6db6d25385359ee82086b510537107fb3d0d0f31 100644
--- a/dbrepo-ui/components/ResourceStatus.vue
+++ b/dbrepo-ui/components/ResourceStatus.vue
@@ -5,7 +5,7 @@
       v-if="!inline"
       :size="size"
       :color="color"
-      variant="outlined">
+      :variant="chipVariant">
       {{ status }}
     </v-chip>
     <span
@@ -14,6 +14,7 @@
     </span>
   </span>
 </template>
+
 <script>
 export default {
   props: {
@@ -38,6 +39,9 @@ export default {
       if (!this.resource) {
         return null
       }
+      if (this.hasIdentifier) {
+        return 'pid'
+      }
       if (!this.resource.is_public && !this.resource.is_schema_public) {
         return 'draft'
       } else if(!this.resource.is_public && this.resource.is_schema_public) {
@@ -53,7 +57,19 @@ export default {
       }
       return this.$t(`pages.database.status.${this.mode}`)
     },
+    hasIdentifier () {
+      return this.resource.identifiers?.length > 0
+    },
+    chipVariant () {
+      if (this.hasIdentifier) {
+        return 'tonal'
+      }
+      return 'outlined'
+    },
     color () {
+      if (this.hasIdentifier) {
+        return 'info'
+      }
       switch (this.mode) {
         case 'schema':
         case 'data':
diff --git a/dbrepo-ui/components/TimeDrift.vue b/dbrepo-ui/components/TimeDrift.vue
deleted file mode 100644
index 2f2555f9f84f107dff1ffd12ad75533d388c1f62..0000000000000000000000000000000000000000
--- a/dbrepo-ui/components/TimeDrift.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-<template>
-  <v-alert
-    v-cloak
-    v-if="timestamp && offSeconds > 3"
-    class="banner"
-    border="start"
-    type="warning">
-    {{ $t('error.data.drift') + ' ' + offSeconds + 's' }}
-  </v-alert>
-</template>
-
-<script>
-import { formatTimestamp, timestampsToHumanDifference } from '@/utils'
-
-export default {
-  data () {
-    return {
-      timestamp: null
-    }
-  },
-  computed: {
-    drift () {
-      return this.timestampsToHumanDifference(Date.now(), this.timestamp)
-    },
-    offSeconds () {
-      if (!this.timestamp) {
-        return null
-      }
-      return (Date.now().valueOf() - Date.parse(this.timestamp)) / 1000
-    }
-  },
-  mounted() {
-    const databaseService = useDatabaseService()
-    databaseService.getServerTime()
-      .then((timestamp) => {
-        this.timestamp = timestamp
-      })
-  },
-  methods: {
-    formatTimestamp,
-    timestampsToHumanDifference
-  }
-}
-</script>
diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue
index 4177ae592cbae97090d0b109c576137b0ee74cbc..3e661cd754b98ca94519bda6a7f4ad49d4ff0378 100644
--- a/dbrepo-ui/components/database/DatabaseToolbar.vue
+++ b/dbrepo-ui/components/database/DatabaseToolbar.vue
@@ -83,7 +83,6 @@
 
 <script>
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 import ResourceStatus from '@/components/ResourceStatus.vue'
 
 export default {
@@ -94,8 +93,7 @@ export default {
     return {
       tab: null,
       error: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -103,13 +101,13 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    user () {
-      return this.userStore.getUser
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     isContrastTheme () {
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast')
@@ -141,12 +139,6 @@ export default {
       }
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
-    canImportCsv () {
-      if (!this.user || !this.hasWriteAccess) {
-        return false
-      }
-      return this.roles.includes('insert-table-data')
-    },
     canCreateSubset () {
       if (!this.database) {
         return false
@@ -157,22 +149,22 @@ export default {
       return this.hasReadAccess
     },
     canCreateView () {
-      if (!this.user || !this.isOwner) {
+      if (!this.cacheUser || !this.isOwner || !this.roles) {
         return false
       }
       return this.roles.includes('create-database-view')
     },
     canCreateTable () {
-      if (!this.user || !this.hasWriteAccess) {
+      if (!this.cacheUser || !this.hasWriteAccess || !this.roles) {
         return false
       }
       return this.roles.includes('create-table')
     },
     isOwner () {
-      if (!this.database || !this.user) {
+      if (!this.database || !this.cacheUser) {
         return false
       }
-      return this.database.owner.username === this.user.username
+      return this.database.owner.id === this.cacheUser.uid
     },
     buttonVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/components/identifier/Banner.vue b/dbrepo-ui/components/identifier/Banner.vue
index 1450347c412727830e07f4fc1e11b857ab22c346..63c2a7153a03d4dd6742920e2e32d0813bbd9036 100644
--- a/dbrepo-ui/components/identifier/Banner.vue
+++ b/dbrepo-ui/components/identifier/Banner.vue
@@ -3,6 +3,7 @@
     {{ prefix }}: <a :href="href">{{ displayName }}</a>
   </div>
 </template>
+
 <script>
 export default {
   props: {
@@ -23,7 +24,7 @@ export default {
       return identifierService.identifierToDisplayName(this.identifier)
     },
     href () {
-      if (!this.identifier || (this.identifier.status && this.identifier.status !== 'published')) {
+      if (!this.identifier) {
         return null
       }
       const identifierService = useIdentifierService()
diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue
index 3dba450e634c6db374ccd28bd327ff2823756f3e..f37c5c6d7d9893562d94393fe6aa19ab3b448d79 100644
--- a/dbrepo-ui/components/identifier/Persist.vue
+++ b/dbrepo-ui/components/identifier/Persist.vue
@@ -12,6 +12,7 @@
       <v-spacer />
       <v-btn
         v-if="canSave"
+        class="mr-2"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null"
         color="secondary"
         variant="flat"
@@ -22,7 +23,7 @@
         @click="createOrSave"/>
       <v-btn
         v-if="canRemove"
-        class="ml-2"
+        class="mr-2"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-delete' : null"
         color="error"
         variant="flat"
@@ -32,7 +33,7 @@
         @click="remove" />
       <v-btn
         v-if="canPublish"
-        class="ml-2"
+        class="mr-2"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null"
         color="primary"
         variant="flat"
@@ -138,14 +139,6 @@
                       :color="canShiftUp(creator, i) ? 'tertiary' : ''"
                       :variant="buttonVariant"
                       @click="shiftDown(i)" />
-                    <v-btn
-                      v-if="canInsertSelf"
-                      class="mr-2"
-                      size="small"
-                      color="secondary"
-                      variant="flat"
-                      :text="$t('pages.identifier.subpages.create.creators.insert.text')"
-                      @click="insertSelf(creator)" />
                     <v-btn
                       v-if="i > 0"
                       size="small"
@@ -830,7 +823,6 @@
 <script>
 import { formatYearUTC, formatMonthUTC, formatDayUTC, languages } from '@/utils'
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 import { MerkleJson } from 'merkle-json'
 
 export default {
@@ -962,16 +954,15 @@ export default {
         { value: 'IsObsoletedBy' },
         { value: 'Obsoletes' }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     isSubset () {
       return this.type === 'subset'
@@ -1045,23 +1036,14 @@ export default {
           }
       }
     },
-    isUpdate () {
-      return 'id' in this.identifier && this.identifier.id
-    },
-    canInsertSelf () {
-      if (!this.user) {
-        return false
-      }
-      return this.user.given_name || this.user.family_name || this.user.attributes.affiliation || this.user.attributes.orcid
-    },
     isCreator () {
-      if (!this.user || !this.identifier) {
+      if (!this.cacheUser || !this.identifier) {
         return false
       }
-      if (!this.identifier.creator) {
+      if (!this.identifier.owner) {
         return true
       }
-      return this.identifier.creator.id === this.user.id
+      return this.identifier.owner.id === this.cacheUser.uid
     },
     formValid () {
       /* somehow Vue3/Vuetify3 validation form is broken for arrays */
@@ -1123,10 +1105,10 @@ export default {
       return this.roles.includes('create-identifier') && !this.isPublished
     },
     canRemove () {
-      if (!this.roles || !this.identifier || !this.identifier.creator || !this.user) {
+      if (!this.roles || !this.identifier || !this.identifier.owner || !this.cacheUser) {
         return false
       }
-      return this.roles.includes('delete-identifier') && this.identifier.creator.id === this.user.id && !this.isPublished
+      return this.roles.includes('delete-identifier') && this.identifier.owner.id === this.cacheUser.uid && !this.isPublished
     },
     canPublish () {
       if (!this.roles || !this.identifier || !this.roles.includes('publish-identifier') || this.isPublished || !this.identifier.id) {
@@ -1494,15 +1476,15 @@ export default {
       if (this.isPublished) {
         return false
       }
-      if (this.user.attributes.orcid) {
-        creator.name_identifier = this.user.attributes.orcid
+      if (this.cacheUser.attributes.orcid) {
+        creator.name_identifier = this.cacheUser.attributes.orcid
         this.retrieveCreator(creator)
         return
       }
-      creator.firstname = this.user.given_name
-      creator.lastname = this.user.family_name
+      creator.firstname = this.cacheUser.given_name
+      creator.lastname = this.cacheUser.family_name
       creator.creator_name = (creator.lastname ? creator.lastname + ', ' : '') + creator.firstname
-      creator.affiliation = this.user.attributes.affiliation
+      creator.affiliation = this.cacheUser.attributes.affiliation
     },
     canShiftUp (creator, idx) {
       if (this.isPublished) {
diff --git a/dbrepo-ui/components/identifier/Select.vue b/dbrepo-ui/components/identifier/Select.vue
index 4404a09635c6833e609f74c4f685988550dc97c8..e5572866140858970c5141d40591af3dda5c389a 100644
--- a/dbrepo-ui/components/identifier/Select.vue
+++ b/dbrepo-ui/components/identifier/Select.vue
@@ -8,7 +8,7 @@
       :color="color(identifier)"
       :variant="listVariant"
       :href="href(identifier)"
-      :title="formatTimestampUTCLabel(identifier.created)"
+      :title="title(identifier)"
       lines="two">
       <v-list-item-subtitle>
         <Banner
@@ -43,8 +43,6 @@
 
 <script>
 import Banner from '@/components/identifier/Banner.vue'
-import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -61,32 +59,31 @@ export default {
     identifier: {
       type: Object,
       default () {
-        return {}
+        return null
       }
     }
   },
   data () {
     return {
       idx: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     displayIdentifiers () {
-      if (!this.identifiers) {
-        return []
+      if (!this.identifiers || this.identifiers.length === 0) {
+        if (!this.identifier) {
+          return []
+        }
+        return [this.identifier]
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return this.identifiers.filter(i => i.status === 'published')
       }
-      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id)
+      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.cacheUser.uid)
     },
     listVariant () {
       const runtimeConfig = useRuntimeConfig()
@@ -105,8 +102,10 @@ export default {
     this.init()
   },
   methods: {
-    formatTimestampUTCLabel,
     href (identifier) {
+      if (!identifier) {
+        return null
+      }
       if (identifier.status === 'published') {
         return `/pid/${identifier.id}`
       }
@@ -121,6 +120,13 @@ export default {
           return `/database/${identifier.database_id}/view/${identifier.view_id}/persist/${identifier.id}`
       }
     },
+    title (identifier) {
+      if (!identifier) {
+        return null
+      }
+      const identifierService = useIdentifierService()
+      return identifierService.identifierPreferEnglishTitle(identifier)
+    },
     isActive (identifier) {
       if (!identifier) {
         return false
diff --git a/dbrepo-ui/components/identifier/Summary.vue b/dbrepo-ui/components/identifier/Summary.vue
index 655a7bb907c9f8a6b868e280097033b157cd893c..6ef120599b515fece88870ad832ed23a508e4ebe 100644
--- a/dbrepo-ui/components/identifier/Summary.vue
+++ b/dbrepo-ui/components/identifier/Summary.vue
@@ -170,10 +170,10 @@ export default {
   },
   computed: {
     access () {
-      return this.userStore.getAccess.value
+      return this.cacheStore.getAccess
     },
     database () {
-      return this.cacheStore.getDatabase.value
+      return this.cacheStore.getDatabase
     },
     pid () {
       return `/pid/${this.database.identifier.id}`
diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue
index b45881479cb5243861ab8137a99999def787e551..f670700f2f23aa2a08a6ecf8004fecfb899c6c00 100644
--- a/dbrepo-ui/components/subset/Builder.vue
+++ b/dbrepo-ui/components/subset/Builder.vue
@@ -31,14 +31,12 @@
           :text="$t('pages.subset.subpages.create.expert.text')" />
       </v-tabs>
     </v-toolbar>
-    <TimeDrift />
     <v-card
       rounded="0"
       variant="flat">
       <v-card-text>
         <v-form
           ref="form"
-          v-model="valid"
           @submit.prevent>
           <v-row
             v-if="isView"
@@ -74,7 +72,7 @@
                 required
                 clearable
                 :rules="[
-                  v => !!v || $t('validation.required')
+                  v => v !== null || $t('validation.required')
                 ]"
                 :label="$t('pages.database.resource.data.label')"
                 :hint="$t('pages.database.resource.data.hint')" />
@@ -89,7 +87,7 @@
                 required
                 clearable
                 :rules="[
-                  v => !!v || $t('validation.required')
+                  v => v !== null || $t('validation.required')
                 ]"
                 :label="$t('pages.database.resource.schema.label')"
                 :hint="$t('pages.database.resource.schema.hint', { resource: 'subset', schema: 'query' })" />
@@ -304,18 +302,15 @@
 </template>
 
 <script>
-import TimeDrift from '@/components/TimeDrift.vue'
 import Raw from '@/components/subset/Raw.vue'
 import Results from '@/components/subset/Results.vue'
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 import { format } from 'sql-formatter'
 
 export default {
   components: {
     Raw,
     Results,
-    TimeDrift
   },
   props: {
     mode: {
@@ -359,8 +354,7 @@ export default {
       tabs: 0,
       loadingQuery: false,
       loadingColumns: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -388,9 +382,6 @@ export default {
       }
       return this.database.container.image.data_types
     },
-    user () {
-      return this.userStore.getUser
-    },
     viewNames () {
       if (!this.database) {
         return []
@@ -449,7 +440,7 @@ export default {
       if (this.isView) {
         return this.view.name !== null && this.view.is_public !== null && this.view.query !== null
       }
-      return this.sql !== null && !this.sql.includes(';')
+      return this.sql !== null && this.sql !== '' && !this.sql.includes(';')
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
@@ -473,7 +464,7 @@ export default {
       if (!this.table) {
         return
       }
-      this.fetchTableColumns(this.table.id)
+      this.fetchTableColumns(this.table?.id)
     }
   },
   mounted () {
@@ -550,13 +541,24 @@ export default {
       this.view.query = this.sql
       const viewService = useViewService()
       viewService.create(this.$route.params.database_id, this.view)
-        .then(async (view) => {
-          this.resultId = view.id
-          this.cacheStore.reloadDatabase()
-          const toast = useToastInstance()
-          toast.success(this.$t('success.view.create'))
-          await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`)
-          this.loadingQuery = false
+        .then((simpleView) => {
+          this.resultId = simpleView.id
+          viewService.findOne(this.$route.params.database_id, simpleView.id)
+            .then(async (view) => {
+              this.cacheStore.setView(view)
+              const toast = useToastInstance()
+              toast.success(this.$t('success.view.create'))
+              await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`)
+              this.loadingQuery = false
+            })
+            .catch(({code}) => {
+              this.loadingQuery = false
+              const toast = useToastInstance()
+              if (typeof code !== 'string') {
+                return
+              }
+              toast.error(this.$t(code))
+            })
         })
         .catch(({code}) => {
           this.loadingQuery = false
diff --git a/dbrepo-ui/components/subset/Results.vue b/dbrepo-ui/components/subset/Results.vue
index 3948667518939fc6ae4d1a5d05502a81e3e14315..661c7d1a3d6e7502cf349a63cc695cf7d593f427 100644
--- a/dbrepo-ui/components/subset/Results.vue
+++ b/dbrepo-ui/components/subset/Results.vue
@@ -80,23 +80,6 @@ export default {
     }
   },
   methods: {
-    executeFirstTime (parent, sql, timestamp) {
-      this.loading++
-      const payload = {
-        statement: sql,
-        timestamp
-      }
-      const queryService = useQueryService()
-      queryService.execute(this.$route.params.database_id, payload, this.options.page - 1, this.options.itemsPerPage)
-        .then((result) => {
-          this.mapResults(result)
-          parent.resultId = result.id
-          this.id = result.id
-        })
-        .finally(() => {
-          this.loading--
-        })
-    },
     reExecute (id) {
       if (id === null) {
         return
diff --git a/dbrepo-ui/components/subset/SubsetList.vue b/dbrepo-ui/components/subset/SubsetList.vue
index 6908b2b4381d88d7b5a7a19ce540b4c88c633e0e..df0948372eed1dbf60260b6f3bd835e51dd93d2a 100644
--- a/dbrepo-ui/components/subset/SubsetList.vue
+++ b/dbrepo-ui/components/subset/SubsetList.vue
@@ -14,28 +14,20 @@
         <Loading />
       </v-list-item>
       <div
-        v-for="(item, i) in subsets"
+        v-for="(subset, i) in subsets"
         :key="`q-${i}`">
         <v-divider v-if="i !== 0" class="mx-4" />
         <v-list>
           <v-list-item
             lines="two"
-            :title="title(item)"
-            :subtitle="subtitle(item)"
-            :class="clazz(item)"
-            :to="link(item)"
-            :href="link(item)">
+            :title="title(subset)"
+            :subtitle="subtitle(subset)"
+            :class="clazz(subset)"
+            :to="link(subset)"
+            :href="link(subset)">
             <template v-slot:append>
-              <v-tooltip
-                v-if="hasPublishedIdentifier(item)"
-                :text="$t('pages.identifier.pid.title')"
-                left>
-                <template v-slot:activator="{ props }">
-                  <v-icon
-                    color="primary"
-                    v-bind="props">mdi-identifier</v-icon>
-                </template>
-              </v-tooltip>
+              <ResourceStatus
+                :resource="subset" />
             </template>
           </v-list-item>
         </v-list>
@@ -45,8 +37,6 @@
 </template>
 
 <script>
-import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -55,14 +45,10 @@ export default {
       loadingSubsets: false,
       loadingIdentifiers: false,
       subsets: [],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -130,7 +116,6 @@ export default {
   }
 }
 </script>
-
 <style lang="scss" scoped>
 .pid-icon {
   flex: 0 !important;
diff --git a/dbrepo-ui/components/subset/SubsetToolbar.vue b/dbrepo-ui/components/subset/SubsetToolbar.vue
index d5f45e48e3a2d596977a37186a0076179bcd583f..e6026090978a3745af50b7e9a3e7a559ae5363a5 100644
--- a/dbrepo-ui/components/subset/SubsetToolbar.vue
+++ b/dbrepo-ui/components/subset/SubsetToolbar.vue
@@ -58,7 +58,6 @@
 <script>
 import DownloadButton from '@/components/identifier/DownloadButton.vue'
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -71,7 +70,6 @@ export default {
       loading: false,
       loadingSave: false,
       downloadLoading: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -86,17 +84,14 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getAccess
     },
     subset () {
       return this.cacheStore.getSubset
     },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
     identifiers () {
       if (!this.subset) {
         return []
@@ -117,9 +112,7 @@ export default {
       if (this.pid) {
         const filter = this.identifiers.filter(i => i.id === Number(this.pid))
         if (filter.length > 0) {
-          const identifier = filter[0]
-          console.debug('identifier set according to route pid', identifier)
-          return identifier
+          return filter[0]
         }
       }
       return this.identifiers[0]
@@ -154,10 +147,10 @@ export default {
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
     canGetPid () {
-      if (!this.user || !this.subset || !this.database) {
+      if (!this.cacheUser || !this.subset || !this.database) {
         return false
       }
-      return this.database.owner.id === this.user.id || (this.subset.owner.id === this.user.id && this.hasReadAccess)
+      return this.database.owner.id === this.cacheUser.uid || (this.subset.owner.id === this.cacheUser.uid && this.hasReadAccess)
     },
     title () {
       if (!this.identifier) {
diff --git a/dbrepo-ui/components/table/TableList.vue b/dbrepo-ui/components/table/TableList.vue
index b78e20ae3a6d423a90a636f119d96e4b406ea45d..5f87090b85855cdc7d6113a9de97bbea18106484 100644
--- a/dbrepo-ui/components/table/TableList.vue
+++ b/dbrepo-ui/components/table/TableList.vue
@@ -21,16 +21,6 @@
           <template v-slot:append>
             <ResourceStatus
               :resource="table" />
-            <v-tooltip
-              v-if="hasPublishedIdentifier(table)"
-              :text="$t('pages.identifier.pid.title')"
-              left>
-              <template v-slot:activator="{ props }">
-                <v-icon
-                  color="primary"
-                  v-bind="props">mdi-identifier</v-icon>
-              </template>
-            </v-tooltip>
           </template>
         </v-list-item>
       </v-list>
@@ -40,7 +30,6 @@
 
 <script>
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -74,19 +63,15 @@ export default {
         { value: 'string', title: 'Character Varying' },
         { value: 'text', title: 'Text' }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     tables () {
       if (!this.database) {
diff --git a/dbrepo-ui/components/table/TableToolbar.vue b/dbrepo-ui/components/table/TableToolbar.vue
index d6fd4868eae0e65a52d932339ba5bbab6e3ad56f..e09cd67cba31e8d3aaec7e9055078fa354bd4ded 100644
--- a/dbrepo-ui/components/table/TableToolbar.vue
+++ b/dbrepo-ui/components/table/TableToolbar.vue
@@ -80,7 +80,6 @@
 <script>
 import EditTuple from '@/components/dialogs/EditTuple.vue'
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -93,8 +92,7 @@ export default {
       error: false,
       edit: false,
       dropTableDialog: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -105,39 +103,42 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
     },
     hasReadAccess () {
       if (!this.access) {
         return false
       }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     canUpdateTable () {
-      if (!this.roles || !this.user || !this.table) {
+      if (!this.roles || !this.cacheUser || !this.table) {
         return false
       }
-      return this.roles.includes('update-table') && this.table.owner.id === this.user.id
+      return this.roles.includes('update-table') && this.table.owner.id === this.cacheUser.uid
     },
     canExecuteQuery () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
-      const userService = useUserService()
-      return userService.hasReadAccess(this.access) && this.roles.includes('execute-query')
+      return this.hasReadAccess && this.roles.includes('execute-query')
+    },
+    isOwner () {
+      const databaseService = useDatabaseService()
+      return databaseService.isOwner(this.database, this.cacheUser)
     },
     canCreateView () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
-      const databaseService = useDatabaseService()
-      return databaseService.isOwner(this.database, this.user) && this.roles.includes('create-database-view')
+      return this.isOwner && this.roles.includes('create-database-view')
     },
     canViewData () {
       if (!this.table) {
@@ -146,10 +147,10 @@ export default {
       if (this.table.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.table.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canViewSchema () {
       if (!this.table) {
@@ -158,22 +159,22 @@ export default {
       if (this.table.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.table.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canImportCsv () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
       return this.roles.includes('insert-table-data')
     },
     canGetPid () {
-      if (!this.user || !this.table || !this.database) {
+      if (!this.cacheUser || !this.table || !this.database) {
         return false
       }
-      return this.database.owner.id === this.user.id || this.table.owner.id === this.user.id
+      return this.hasReadAccess && this.database.owner.id === this.cacheUser.uid || this.table.owner.id === this.cacheUser.uid
     },
     buttonVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/components/user/UserToolbar.vue b/dbrepo-ui/components/user/UserToolbar.vue
index e5a20c75a3230d80dc3e6f63c27c5bb6a743a463..54210130d32f9c1cbe73378138e6c0db28c8cc88 100644
--- a/dbrepo-ui/components/user/UserToolbar.vue
+++ b/dbrepo-ui/components/user/UserToolbar.vue
@@ -1,6 +1,9 @@
 <template>
-  <div>
-    <v-toolbar title="Settings" flat>
+  <div
+    v-if="loggedIn">
+    <v-toolbar
+      title="Settings"
+      flat>
       <template v-slot:extension>
         <v-tabs
           v-model="tab"
@@ -11,31 +14,20 @@
           <v-tab
             :text="$t('toolbars.user.authentication')"
             to="/user/authentication" />
-          <v-tab
-            :text="$t('toolbars.user.developer')"
-            to="/user/developer" />
         </v-tabs>
       </template>
     </v-toolbar>
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
-import { useUserStore } from '@/stores/user.js'
-
 export default {
   data () {
     return {
       tab: null,
-      userStore: useUserStore()
-    }
-  },
-  computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
     }
   }
 }
diff --git a/dbrepo-ui/components/view/ViewList.vue b/dbrepo-ui/components/view/ViewList.vue
index d6539bd253cb7ef40c202633db53d564ec1e6269..afa3067921b10d1c1f2fe6d78cac4e9c7781bebe 100644
--- a/dbrepo-ui/components/view/ViewList.vue
+++ b/dbrepo-ui/components/view/ViewList.vue
@@ -16,16 +16,6 @@
           <template v-slot:append>
             <ResourceStatus
               :resource="view" />
-            <v-tooltip
-              v-if="hasPublishedIdentifier(view)"
-              :text="$t('pages.identifier.pid.title')"
-              left>
-              <template v-slot:activator="{ props }">
-                <v-icon
-                  color="primary"
-                  v-bind="props">mdi-identifier</v-icon>
-              </template>
-            </v-tooltip>
           </template>
         </v-list-item>
       </v-list>
@@ -34,7 +24,6 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -43,14 +32,10 @@ export default {
       loading: false,
       loadingDetails: false,
       error: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
diff --git a/dbrepo-ui/components/view/ViewToolbar.vue b/dbrepo-ui/components/view/ViewToolbar.vue
index 4ed83ff43fa777f9f8f663cf020d89d5d58456cd..d9e0bfb6bf6740c19aac53f6b3ac8cc374be7011 100644
--- a/dbrepo-ui/components/view/ViewToolbar.vue
+++ b/dbrepo-ui/components/view/ViewToolbar.vue
@@ -57,7 +57,6 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import CreateOntology from '@/components/dialogs/CreateOntology.vue'
 import ViewVisibility from '@/components/dialogs/ViewVisibility.vue'
@@ -73,7 +72,6 @@ export default {
       loading: false,
       loadingDelete: false,
       updateViewDialog: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -91,6 +89,12 @@ export default {
     view () {
       return this.cacheStore.getView
     },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
     canViewData () {
       if (!this.view) {
         return false
@@ -98,10 +102,10 @@ export default {
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.view.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canViewSchema () {
       if (!this.view) {
@@ -110,32 +114,26 @@ export default {
       if (this.view.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
+      return this.hasReadAccess || this.view.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid
     },
     canViewSettings () {
-      if (!this.user || !this.view) {
+      if (!this.cacheUser || !this.view) {
         return false
       }
-      return this.view.owner.id === this.user.id
+      return this.view.owner.id === this.cacheUser.uid
     },
     canCreatePid () {
-      if (!this.roles || !this.user || !this.view) {
+      if (!this.roles || !this.cacheUser || !this.view) {
         return false
       }
-      const userService = useUserService()
-      return this.roles.includes('create-identifier') && userService.hasReadAccess(this.access)
+      const cacheUserService = useUserService()
+      return cacheUserService.hasReadAccess(this.access) && this.roles.includes('create-identifier')
     },
     access () {
-      return this.userStore.getAccess
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
diff --git a/dbrepo-ui/composables/axios-instance.ts b/dbrepo-ui/composables/axios-instance.ts
index 95edea3c28d5c12f1f2422ccf8b457e409c5b459..ca7a7b111cf70cf92524f5459808277e4b14144e 100644
--- a/dbrepo-ui/composables/axios-instance.ts
+++ b/dbrepo-ui/composables/axios-instance.ts
@@ -1,11 +1,9 @@
 import axios, {type AxiosInstance} from 'axios'
-import {useUserStore} from '@/stores/user'
 
 let instance: AxiosInstance | null = null;
 
 export const useAxiosInstance = () => {
   const config = useRuntimeConfig()
-  const userStore = useUserStore()
   if (!instance) {
     instance = axios.create({
       timeout: 90_000,
@@ -18,38 +16,16 @@ export const useAxiosInstance = () => {
       baseURL: config.public.api.client
     });
     instance.interceptors.request.use((config) => {
-      const token = userStore.getToken
-      const refreshToken = userStore.getRefreshToken
-      if (!token || !refreshToken) {
+      const { loggedIn, user, login, logout } = useOidcAuth()
+      if (!loggedIn) {
         return config
       }
-      const authenticationService = useAuthenticationService()
-      if (authenticationService.isExpiredToken(refreshToken)) {
-        console.warn('Refresh token is expired: trigger logout of user')
-        userStore.logout()
+      const { accessToken } = user.value
+      if (!accessToken) {
         return config
       }
-      if (!authenticationService.isExpiredToken(token)) {
-        config.headers.Authorization = `Bearer ${token}`
-        return config
-      }
-      console.warn('Access token expired: request a new one')
-      const userService = useUserService()
-      return userService.refreshToken(refreshToken)
-        .then((response: KeycloakOpenIdTokenDto) => {
-          userStore.setToken(response.access_token)
-          userStore.setRefreshToken(response.refresh_token)
-          console.debug('new access token expires:', authenticationService.tokenToExpiryDate(response.access_token))
-          config.headers.Authorization = `Bearer ${response.access_token}`
-          return config
-        })
-        .catch((error: ApiErrorDto) => {
-          if (error.code === 'error.user.credentials') {
-            console.warn('User session expired.')
-            userStore.logout()
-          }
-          return config
-        });
+      config.headers.Authorization = `Bearer ${accessToken}`
+      return config
     })
   }
   return instance;
diff --git a/dbrepo-ui/composables/database-service.ts b/dbrepo-ui/composables/database-service.ts
index 7956f7b4dff6cb748733fd381275dd6d0622b60c..f318e073054d6a4283b654bbae985b4f903aec00 100644
--- a/dbrepo-ui/composables/database-service.ts
+++ b/dbrepo-ui/composables/database-service.ts
@@ -66,23 +66,6 @@ export const useDatabaseService = (): any => {
     });
   }
 
-  async function getServerTime(): Promise<Date> {
-    const axios = useAxiosInstance();
-    console.debug('find server time');
-    return new Promise<Date>((resolve, reject) => {
-      axios.head<Date>('/api/database')
-        .then((response) => {
-          const date: Date = new Date(response.headers['Date'])
-          console.info(`Found ${date} server time`);
-          resolve(date);
-        })
-        .catch((error) => {
-          console.error('Failed to find server time', error);
-          reject(axiosErrorToApiError(error));
-        });
-    });
-  }
-
   async function findOne(id: number, rawError: boolean = false): Promise<DatabaseDto | null> {
     const axios = useAxiosInstance();
     console.debug('find database with id', id);
@@ -239,16 +222,12 @@ export const useDatabaseService = (): any => {
     refreshTablesMetadata,
     refreshViewsMetadata,
     findOne,
-    findPreviewImage,
-    findCount,
-    getServerTime,
     updateVisibility,
     updateImage,
     updateOwner,
     create,
     databaseToOwner,
     databaseToContact,
-    databaseToJsonLd,
     isOwner
   }
 }
diff --git a/dbrepo-ui/composables/identifier-service.ts b/dbrepo-ui/composables/identifier-service.ts
index 3ae194ff2fcaf85110e61eb710f7981ffc74e67a..6875a7cb7b2c168ecfb7357cc314219792930bf8 100644
--- a/dbrepo-ui/composables/identifier-service.ts
+++ b/dbrepo-ui/composables/identifier-service.ts
@@ -24,7 +24,7 @@ export const useIdentifierService = (): any => {
   }
 
   async function create(data: IdentifierSaveDto): Promise<IdentifierDto> {
-    const axios= useAxiosInstance()
+    const axios = useAxiosInstance()
     console.debug('create identifier')
     return new Promise<IdentifierDto>((resolve, reject) => {
       axios.post<IdentifierDto>('/api/identifier', data)
@@ -40,7 +40,7 @@ export const useIdentifierService = (): any => {
   }
 
   async function save(data: IdentifierSaveDto): Promise<IdentifierDto> {
-    const axios= useAxiosInstance()
+    const axios = useAxiosInstance()
     console.debug('save identifier', data.id)
     return new Promise<IdentifierDto>((resolve, reject) => {
       axios.put<IdentifierDto>(`/api/identifier/${data.id}`, data)
@@ -241,13 +241,28 @@ export const useIdentifierService = (): any => {
     if (!data || !data.titles || data.titles.length === 0) {
       return null
     }
-    const filtered = data.titles.filter(d => d.language && d.language === 'en')
+    const filtered = data.titles.filter((d) => d.language && d.language === 'en')
     if (filtered.length === 0) {
-      return data.titles[0].title
+      const title = data.titles[0]
+      return title.title
     }
     return filtered[0].title
   }
 
+  function identifierToResourceUrl(identifier: IdentifierDto): string | null {
+    const config = useRuntimeConfig()
+    switch (identifier.type) {
+      case 1:
+        return `${config.public.api.client}/api/database/${identifier.database_id}/subset/${identifier.subset_id}/data`
+      case 2:
+        return `${config.public.api.client}/api/database/${identifier.database_id}/table/${identifier.table_id}/data`
+      case 3:
+        return `${config.public.api.client}/api/database/${identifier.database_id}/view/${identifier.view_id}/data`
+      default:
+        return null
+    }
+  }
+
   function identifierToUrl(data: IdentifierDto): string | null {
     if (!data) {
       return null
@@ -315,244 +330,48 @@ export const useIdentifierService = (): any => {
     return jsonLd
   }
 
-  function identifierToHasPartJsonLd(identifier: IdentifierDto) {
-    return {
-      '@type': 'Dataset',
-      name: identifierPreferEnglishTitle(identifier),
-      description: identifierPreferEnglishDescription(identifier),
-      identifier: identifierToUrl(identifier),
-      citation: identifierToUrl(identifier),
-      temporalCoverage: identifier.publication_year,
-      version: identifier.created
-    }
-  }
-
-  function databaseToServerHead(database: DatabaseDto) {
-    if (!database) {
-      return
+  function identifiersToServerHead(identifiers: IdentifierBriefDto[]): any {
+    if (!identifiers || !identifiers[0]) {
+      return null
     }
-    const config = useRuntimeConfig()
+    const identifier = identifiers[0]
     /* Google Rich Results */
     const json: any = {
       '@context': 'https://schema.org/',
       '@type': 'Dataset',
-      url: `${config.public.api.client}/database/${database.id}/info`,
-      citation: `${config.public.api.client}/database/${database.id}/info`,
+      url: identifierToUrl(identifier),
+      citation: identifierToUrl(identifier),
       hasPart: [],
-      version: database.created
+      identifier: identifiers.map(i => identifierToUrl(i)),
+      creator: identifier.creators.map((c) => creatorToCreatorJsonLd(c)),
+      temporalCoverage: identifier.publication_year
     }
-    /* FAIR Signposting */
-    const meta: any [] = []
-    if (database.identifiers.length > 0) {
-      const identifier = database.identifiers[0]
-      const partIdentifiers: IdentifierDto[] = []
-      if (database.subsets.length > 0) {
-        database.subsets.forEach((s) => {
-          partIdentifiers.push(s)
-        })
-      }
-      if (database.tables.length > 0) {
-        database.tables.forEach((t) => {
-          if (t.identifiers.length > 0) {
-            t.identifiers.forEach(i => partIdentifiers.push(i))
-          }
-        })
-      }
-      if (database.views.length > 0) {
-        database.views.forEach((v) => {
-          if (v.identifiers.length > 0) {
-            v.identifiers.forEach(i => partIdentifiers.push(i))
-          }
-        })
-      }
+    if (identifier.titles.length > 0) {
       json['name'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = database.identifiers.map(i => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['hasPart'] = partIdentifiers.map(i => identifierToHasPartJsonLd(i))
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto) => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
-      }
-    }
-    return {
-      script: [
-        {
-          type: 'application/ld+json',
-          innerHTML: json
-        }
-      ],
-      link: meta
     }
-  }
-
-  function subsetToServerHead(subset: QueryDto) {
-    const config = useRuntimeConfig()
-    /* Google Rich Results */
-    const json: any = {
-      '@context': 'https://schema.org/',
-      '@type': 'Dataset',
-      description: subset.query,
-      url: `${config.public.api.client}/database/${subset.database_id}/info`,
-      citation: `${config.public.api.client}/database/${subset.database_id}/info`,
-      hasPart: [],
-      version: subset.created
-    }
-    /* FAIR Signposting */
-    const meta: any[] = []
-    if (subset.identifiers.length > 0) {
-      const identifier = subset.identifiers[0]
-      json['name'] = identifierPreferEnglishTitle(identifier)
+    if (identifier.descriptions.length > 0) {
       json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = subset.identifiers.map(i => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto) => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
-      }
-      meta.push({
-        rel: 'item',
-        type: 'application/json',
-        href: `${config.public.api.client}/api/database/${subset.database_id}/subset/${subset.id}/data`
-      })
-      meta.push({
-        rel: 'item',
-        type: 'text/csv',
-        href: `${config.public.api.client}/api/database/${subset.database_id}/subset/${subset.id}/data`
-      })
-    }
-    return {
-      script: [
-        {
-          type: 'application/ld+json',
-          innerHTML: json
-        }
-      ],
-      link: meta
-    }
-  }
-
-  function tableToServerHead(table: TableDto) {
-    const config = useRuntimeConfig()
-    /* Google Rich Results */
-    const json: any = {
-      '@context': 'https://schema.org/',
-      '@type': 'Dataset',
-      description: table.description,
-      url: `${config.public.api.client}/database/${table.database_id}/table/${table.id}/info`,
-      citation: `${config.public.api.client}/database/${table.database_id}/table/${table.id}/info`,
-      hasPart: [],
-      version: table.created
     }
     /* FAIR Signposting */
     const meta: any[] = []
-    if (table.identifiers.length > 0) {
-      const identifier: IdentifierDto = table.identifiers[0]
-      json['name'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = table.identifiers.map((i: IdentifierDto) => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map((c: CreatorDto) => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto): void => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
+    meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
+    identifier.creators.forEach((c: CreatorDto) => {
+      if (c.name_identifier) {
+        meta.push({rel: 'author', href: c.name_identifier})
       }
-      meta.push({
-        rel: 'item',
-        type: 'application/json',
-        href: `${config.public.api.client}/api/database/${table.database_id}/table/${table.id}/data`
-      })
-      meta.push({
-        rel: 'item',
-        type: 'text/csv',
-        href: `${config.public.api.client}/api/database/${table.database_id}/table/${table.id}/data`
-      })
-    }
-    return {
-      script: [
-        {
-          type: 'application/ld+json',
-          innerHTML: json
-        }
-      ],
-      link: meta
-    }
-  }
-
-  function viewToServerHead(view: ViewDto) {
-    const config = useRuntimeConfig()
-    /* Google Rich Results */
-    const json: any = {
-      '@context': 'https://schema.org/',
-      '@type': 'Dataset',
-      description: view.query,
-      url: `${config.public.api.client}/database/${view.database_id}/table/${view.id}/info`,
-      citation: `${config.public.api.client}/database/${view.database_id}/table/${view.id}/info`,
-      hasPart: [],
-      version: view.created
-    }
-    /* FAIR Signposting */
-    const meta: any[] = []
-    if (view.identifiers.length > 0) {
-      const identifier = view.identifiers[0]
-      json['name'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['identifier'] = view.identifiers.map(i => identifierToUrl(i))
-      json['license'] = identifierToPreferFirstLicenseUri(identifier)
-      json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c))
-      json['citation'] = identifierToUrl(identifier)
-      json['temporalCoverage'] = identifier.publication_year
-      meta.push({rel: 'cite-as', href: identifierToUrl(identifier)})
-      identifier.creators.forEach((c: CreatorDto) => {
-        if (c.name_identifier) {
-          meta.push({rel: 'author', href: c.name_identifier})
-        }
-      })
-      meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
-      meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
-      if (identifier.licenses) {
-        identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri}))
-      }
-      meta.push({
-        rel: 'item',
-        type: 'application/json',
-        href: `${config.public.api.client}/api/database/${view.database_id}/view/${view.id}/data`
-      })
-      meta.push({
-        rel: 'item',
-        type: 'text/csv',
-        href: `${config.public.api.client}/api/database/${view.database_id}/view/${view.id}/data`
-      })
-    }
+    })
+    meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)})
+    meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)})
+    meta.push({
+      rel: 'item',
+      type: 'application/json',
+      href: identifierToResourceUrl(identifier)
+    })
+    meta.push({
+      rel: 'item',
+      type: 'text/csv',
+      href: identifierToResourceUrl(identifier)
+    })
     return {
       script: [
         {
@@ -564,56 +383,15 @@ export const useIdentifierService = (): any => {
     }
   }
 
-  function databaseToServerSeoMeta(database: DatabaseDto) {
-    const json: any = {
-      ogTitle: database.name
-    }
-    if (database.identifiers.length > 0) {
-      const identifier = database.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
-    }
-    return json
-  }
-
-  function subsetToServerSeoMeta(subset: QueryDto) {
-    const json: any = {
-      description: subset.query
-    }
-    if (subset.identifiers.length > 0) {
-      const identifier = subset.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
-    }
-    return json
-  }
-
-  function tableToServerSeoMeta(table: TableDto) {
-    const json: any = {
-      ogTitle: table.name,
-      description: table.description
-    }
-    if (table.identifiers.length > 0) {
-      const identifier = table.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
+  function identifiersToServerSeoMeta(identifiers: IdentifierBriefDto[]): any | null {
+    if (!identifiers|| !identifiers[0]) {
+      return null
     }
-    return json
-  }
-
-  function viewToServerSeoMeta(view: ViewDto) {
+    const identifier = identifiers[0]
     const json: any = {
-      ogTitle: view.name,
-      description: view.query
-    }
-    if (view.identifiers.length > 0) {
-      const identifier = view.identifiers[0]
-      json['ogTitle'] = identifierPreferEnglishTitle(identifier)
-      json['description'] = identifierPreferEnglishDescription(identifier)
-      json['ogDescription'] = identifierPreferEnglishDescription(identifier)
+      ogTitle: identifierPreferEnglishTitle(identifier),
+      ogDescription: identifierPreferEnglishDescription(identifier),
+      description: identifierPreferEnglishDescription(identifier)
     }
     return json
   }
@@ -633,13 +411,7 @@ export const useIdentifierService = (): any => {
     identifierToUrl,
     identifierToDisplayName,
     identifierToDisplayAcronym,
-    databaseToServerHead,
-    subsetToServerHead,
-    tableToServerHead,
-    viewToServerHead,
-    databaseToServerSeoMeta,
-    subsetToServerSeoMeta,
-    tableToServerSeoMeta,
-    viewToServerSeoMeta,
+    identifiersToServerHead,
+    identifiersToServerSeoMeta
   }
 }
diff --git a/dbrepo-ui/composables/query-service.ts b/dbrepo-ui/composables/query-service.ts
index 119915de2785763d549bdf3bf2d97379811f8fed..e314993ecd233c486198f7995dff4da5389eb06f 100644
--- a/dbrepo-ui/composables/query-service.ts
+++ b/dbrepo-ui/composables/query-service.ts
@@ -161,12 +161,12 @@ export const useQueryService = (): any => {
           }
         }
         sql += ` \`${clause.params[0]}\` ${clause.params[1]} `
-        const filteredType = types.filter(t => t.value === filteredColumn[0].column_type)
+        const filteredType = types.filter(t => t.value === filteredColumn[0].type)
         if (filteredType.length === 0) {
           return {
             error: true,
             reason: 'exists',
-            column: filteredColumn[0].column_type,
+            column: filteredColumn[0].type,
             raw: null,
             formatted: null
           }
@@ -175,7 +175,7 @@ export const useQueryService = (): any => {
           return {
             error: true,
             reason: 'build',
-            column: filteredColumn[0].column_type,
+            column: filteredColumn[0].type,
             raw: null,
             formatted: null
           }
diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts
index 45268d6295fc0ba55fdf268936a1614b350033e3..5f290745245b46a8ce395a489f62aa9171800d5a 100644
--- a/dbrepo-ui/composables/table-service.ts
+++ b/dbrepo-ui/composables/table-service.ts
@@ -255,7 +255,7 @@ export const useTableService = (): any => {
     if (!table || !user) {
       return false
     }
-    return table.owner.id === user.id
+    return table.owner.id === user.uid
   }
 
   function tableNameToInternalName(name: string) {
diff --git a/dbrepo-ui/composables/upload-service.ts b/dbrepo-ui/composables/upload-service.ts
index f7a6964d58cba007c3aa7e515f362349ca0a4f4a..ee0bdd5dc029a061ee102a9e526933ef7ca26413 100644
--- a/dbrepo-ui/composables/upload-service.ts
+++ b/dbrepo-ui/composables/upload-service.ts
@@ -1,11 +1,9 @@
 import * as tus from 'tus-js-client'
 import {useCacheStore} from '@/stores/cache'
-import {useUserStore} from '@/stores/user'
 
 export const useUploadService = (): any => {
 
   function create (data: File) {
-    const userStore = useUserStore()
     const config = useRuntimeConfig()
     const endpoint = config.public.upload.client
     return new Promise<string>((resolve, reject) => {
@@ -13,10 +11,16 @@ export const useUploadService = (): any => {
         console.error('Your browser does not support uploads!')
         return
       }
+      const { loggedIn, user, login, logout } = useOidcAuth()
+      if (!loggedIn || !user.value?.accessToken) {
+        console.error('Please login to use the upload!')
+        return
+      }
+      const { accessToken } = user.value
       const uploadClient: tus.Upload = new tus.Upload(data, {
         endpoint,
         headers: {
-          'Authorization': `Bearer ${userStore.getToken}`
+          'Authorization': `Bearer ${accessToken}`
         },
         retryDelays: [0, 3000, 5000, 10000, 20000],
         onError (error) {
diff --git a/dbrepo-ui/composables/user-service.ts b/dbrepo-ui/composables/user-service.ts
index e68b914e0e5bd5cfc410b82213e18f3eb0fa32ab..3425dbaa5c7d77d927798914b8a4fdac6123c166 100644
--- a/dbrepo-ui/composables/user-service.ts
+++ b/dbrepo-ui/composables/user-service.ts
@@ -80,32 +80,6 @@ export const useUserService = (): any => {
     })
   }
 
-  async function obtainToken(username: string, password: string): Promise<KeycloakOpenIdTokenDto> {
-    console.debug('obtain user token for user with username', username)
-    return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => {
-      const config = useRuntimeConfig()
-      const userStore = useUserStore()
-      const instance = axios.create({
-        timeout: 90_000,
-        params: {},
-        baseURL: config.public.api.client
-      })
-      instance.post<KeycloakOpenIdTokenDto>('/api/user/token', {username, password})
-        .then((response) => {
-          console.info('Obtained user token')
-          // eslint-disable-next-line camelcase
-          const {access_token, refresh_token} = response.data
-          userStore.setToken(access_token)
-          userStore.setRefreshToken(refresh_token)
-          userStore.setRoles(tokenToRoles(access_token))
-          resolve(response.data)
-        }).catch((error) => {
-          console.error('Failed to obtain user token', error)
-          reject(axiosErrorToApiError(error))
-      })
-    })
-  }
-
   async function refreshToken(refreshToken: string): Promise<KeycloakOpenIdTokenDto> {
     console.debug('refresh user token')
     return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => {
@@ -136,21 +110,6 @@ export const useUserService = (): any => {
     return data.realm_access.roles || []
   }
 
-  function tokenToUserId(token: string): string {
-    const data: Token = jwtDecode<Token>(token)
-    return data.uid
-  }
-
-  function userInfoToUser(data: UserDto) {
-    const obj: UserDto = Object.assign({}, data)
-    obj.attributes = {
-      theme: data.attributes.theme,
-      orcid: data.attributes.orcid,
-      affiliation: data.attributes.affiliation
-    }
-    return obj
-  }
-
   function nameIdentifierToNameIdentifierScheme(nameIdentifier: string) {
     if (nameIdentifier.includes('orcid.org')) {
       return 'ORCID'
@@ -182,13 +141,13 @@ export const useUserService = (): any => {
   }
 
   function hasWriteAccess(table: TableDto, access: DatabaseAccessDto, user: UserDto): boolean {
-    if (!table || !access) {
+    if (!table || !access || !user) {
       return false
     }
     if (access.type === 'write_all') {
       return true
     }
-    return access.type === 'write_own' && table.owner.id === user.id
+    return access.type === 'write_own' && table.owner.id === user.uid
   }
 
   return {
@@ -197,11 +156,6 @@ export const useUserService = (): any => {
     update,
     create,
     updatePassword,
-    obtainToken,
-    refreshToken,
-    tokenToRoles,
-    tokenToUserId,
-    userInfoToUser,
     nameIdentifierToNameIdentifierScheme,
     userToFullName,
     hasReadAccess,
diff --git a/dbrepo-ui/dto/index.ts b/dbrepo-ui/dto/index.ts
index 9171734aa350f242d2f38b0d0d0f795871f0306d..605a7c0db9984525632570c70e76dd542845f225 100644
--- a/dbrepo-ui/dto/index.ts
+++ b/dbrepo-ui/dto/index.ts
@@ -224,7 +224,11 @@ interface IdentifierFunderSaveDto {
 
 interface IdentifierDto {
   id: number;
-  type: string;
+  database_id: number | null;
+  query_id: number | null;
+  table_id: number | null;
+  view_id: number | null;
+  type: IdentifierTypeDto;
   titles: IdentifierTitleDto[] | [];
   descriptions: IdentifierDescriptionDto[] | [];
   funders: IdentifierFunderDto[] | [];
@@ -236,23 +240,43 @@ interface IdentifierDto {
   licenses: LicenseDto[] | [];
   creators: CreatorDto[] | [];
   created: Date;
-  database_id: number | null;
-  query_id: number | null;
-  table_id: number | null;
-  view_id: number | null;
   query_normalized: string | null;
   related_identifiers: RelatedIdentifierDto[] | [];
   query_hash: string | null;
   result_hash: string | null;
-  /**
-   * @deprecated
-   */
   result_number: number | null;
   publication_day: number | null;
   publication_month: number | null;
-  value: string | null;
   publication_year: number;
-  last_modified: Date;
+}
+
+enum IdentifierTypeDto {
+  database,
+  subset,
+  table,
+  view
+}
+
+enum IdentifierStatusTypeDto {
+  draft,
+  published
+}
+
+interface IdentifierBriefDto {
+  id: number;
+  database_id: number | null;
+  query_id: number | null;
+  table_id: number | null;
+  view_id: number | null;
+  type: IdentifierTypeDto;
+  creators: CreatorBriefDto[] | [];
+  titles: IdentifierTitleDto[] | [];
+  description: IdentifierDescriptionDto[] | [];
+  doi: string | null;
+  publisher: string;
+  publication_year: number;
+  status: IdentifierStatusTypeDto;
+  owned_by: string;
 }
 
 interface IdentifierTitleDto {
@@ -279,19 +303,35 @@ interface IdentifierFunderDto {
   award_title: string;
 }
 
+enum NameTypeDto {
+  Personal,
+  Organizational
+}
+
 interface CreatorDto {
   id: number;
   firstname: string;
   lastname: string;
   affiliation: string;
   creator_name: string;
-  name_type: string;
-  name_identifier: string;
-  name_identifier_scheme: string;
-  name_identifier_scheme_uri: string;
-  affiliation_identifier: string;
-  affiliation_identifier_scheme: string;
-  affiliation_identifier_scheme_uri: string;
+  name_type: NameTypeDto | null;
+  name_identifier: string | null;
+  name_identifier_scheme: string | null;
+  name_identifier_scheme_uri: string | null;
+  affiliation_identifier: string | null;
+  affiliation_identifier_scheme: string | null;
+  affiliation_identifier_scheme_uri: string | null;
+}
+
+interface CreatorBriefDto {
+  id: number;
+  affiliation: string;
+  creator_name: string;
+  name_type: NameTypeDto | null;
+  name_identifier: string | null;
+  name_identifier_scheme: string | null;
+  affiliation_identifier: string | null;
+  affiliation_identifier_scheme: string | null;
 }
 
 interface RelatedIdentifierDto {
@@ -342,7 +382,6 @@ interface ColumnDto {
   database_id: number;
   table_id: number;
   internal_name: string;
-  date_format: ImageDateDto;
   is_primary_key: boolean;
   index_length: number;
   length: number;
diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue
index 0ad4cb818d353d283c15d0cc7c6240fec513a54b..3ac8e32f900e9b2b95cfb5ab3dc6929a5aae7684 100644
--- a/dbrepo-ui/layouts/default.vue
+++ b/dbrepo-ui/layouts/default.vue
@@ -96,29 +96,22 @@
           @click:append-inner="retrieve" />
         <v-spacer />
         <v-btn
-          v-if="!user"
+          v-if="!loggedIn"
           class="mr-2"
           color="secondary"
           variant="flat"
+          :loading="loadingLogin"
           :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-login' : null"
-          to="/login">
+          @click="loadingLogin=true;login()">
           {{ $t('navigation.login') }}
         </v-btn>
         <v-btn
-          v-if="!user"
-          color="primary"
-          variant="flat"
-          :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-account-plus' : null"
-          to="/signup">
-          {{ $t('navigation.signup') }}
-        </v-btn>
-        <v-btn
-          v-if="user"
+          v-if="cacheUser"
           to="/user"
           variant="plain"
-          :text="user.username" />
+          :text="cacheUser.preferred_username" />
         <v-menu
-          v-if="user"
+          v-if="loggedIn"
           location="bottom">
           <template v-slot:activator="{ props }">
             <v-btn
@@ -127,20 +120,19 @@
           </template>
           <v-list>
             <v-list-item
-              v-if="user"
+              v-if="cacheUser"
               exact
-              :to="`/search?type=database&owner.username=${user.username}`">
+              :to="`/search?type=database&owner.username=${cacheUser.username}`">
               {{ $t('navigation.databases') + ' ' + $t('navigation.mine')}}
             </v-list-item>
             <v-list-item
-              v-if="user"
+              v-if="cacheUser"
               exact
-              :to="`/search?type=identifier&identifiers.creator.username=${user.username}`">
+              :to="`/search?type=identifier&identifiers.creator.username=${cacheUser.username}`">
               {{ $t('navigation.identifiers') + ' ' + $t('navigation.mine') }}
             </v-list-item>
             <v-list-item
-              v-if="user"
-              @click="logout">
+              @click="logout()">
               {{ $t('navigation.logout') }}
             </v-list-item>
           </v-list>
@@ -161,10 +153,13 @@
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { useCacheStore } from '@/stores/cache.js'
 
+const { loggedIn, user, login, logout } = useOidcAuth()
+const cacheStore = useCacheStore()
+cacheStore.setUser(loggedIn ? user.value?.userInfo : null)
+cacheStore.setRoles(loggedIn ? user.value?.claims?.realm_access?.roles : [])
 const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
 useServerHead({
   title: runtimeConfig.public.title,
   meta: [
@@ -175,9 +170,9 @@ useServerHead({
 </script>
 <script>
 import JumboBox from '@/components/JumboBox.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import { errorCodeKey, makeError } from '@/utils'
+import {useNuxtApp} from "#app";
 
 export default {
   components: {
@@ -189,6 +184,7 @@ export default {
       model: null,
       query: null,
       loading: true,
+      loadingLogin: false,
       databaseError: null,
       accessError: null,
       searchResults: [],
@@ -197,26 +193,13 @@ export default {
       loadingSearch: false,
       loadingDatabases: false,
       search: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    locale () {
-      return this.userStore.getLocale
-    },
     messages () {
       return this.cacheStore.getMessages
     },
-    access () {
-      return this.userStore.getAccess
-    },
     table () {
       return this.cacheStore.getTable
     },
@@ -229,6 +212,18 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    identifier () {
+      return this.cacheStore.getIdentifier
+    },
     resource () {
       if (!this.$route.params.database_id) {
         return null
@@ -244,9 +239,6 @@ export default {
       }
       return 'database'
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     version () {
       return this.$config.public.version
     },
@@ -260,22 +252,25 @@ export default {
       return this.$config.public.commit.substr(0, 8)
     },
     error () {
+      if (this.identifier) {
+        return null
+      }
       if (this.databaseError) {
         return this.databaseError
       }
       if (this.accessError) {
         return this.accessError
       }
-      if (!this.user) {
+      if (!this.cacheUser) {
         return null
       }
-      if (this.table && !this.table.is_public && !this.table.is_schema_public && this.table.owner.id !== this.user.id) {
+      if (this.table && !this.table.is_public && !this.table.is_schema_public && !this.access) {
         return makeError(403, null, null)
       }
-      if (this.view && !this.view.is_public && !this.view.is_schema_public && this.view.owner.id !== this.user.id) {
+      if (this.view && !this.view.is_public && !this.view.is_schema_public && !this.access) {
         return makeError(403, null, null)
       }
-      if (this.subset && !this.subset.is_public && !this.subset.is_schema_public && this.subset.owner.id !== this.user.id) {
+      if (this.subset && !this.subset.is_public && !this.subset.is_schema_public && !this.access) {
         return makeError(403, null, null)
       }
       return null
@@ -287,41 +282,53 @@ export default {
       return this.roles.includes('list-ontologies')
     },
     canListContainers () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-containers')
+      return this.cacheUser
     },
     logo () {
       return this.$config.public.logo
     },
+    locale () {
+      return this.cacheStore.getLocale
+    },
     searchVariant () {
       const runtimeConfig = useRuntimeConfig()
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : 'solo-filled'
-    },
+    }
   },
   watch: {
     '$route.params': {
       handler (newObj, oldObj) {
+        if (import.meta.server) {
+          return
+        }
         if (!newObj.database_id) {
           this.databaseError = null
           this.accessError = null
           this.cacheStore.setTable(null)
           this.cacheStore.setView(null)
           this.cacheStore.setSubset(null)
+          this.cacheStore.setAccess(null)
+          this.cacheStore.setIdentifier(null)
           return
         }
-        if (import.meta.server) {
-          return
+        if (this.identifier) {
+          if (newObj.query_id && this.identifier.query_id !== Number(newObj.query_id)) {
+            this.cacheStore.setIdentifier(null)
+          } else if (newObj.table_id && this.identifier.table_id !== Number(newObj.table_id)) {
+            this.cacheStore.setIdentifier(null)
+          } else if (newObj.view_id && this.identifier.view_id !== Number(newObj.view_id)) {
+            this.cacheStore.setIdentifier(null)
+          }
+          if (this.$route.query.pid && this.identifier.id !== Number(this.$route.query.pid)) {
+            this.cacheStore.setIdentifier(null)
+          }
         }
         /* load database and optional access */
+        this.cacheStore.setRouteAccess(newObj.database_id, this.cacheUser?.uid)
         this.cacheStore.setRouteDatabase(newObj.database_id)
           .catch((error) => {
             this.databaseError = error
           })
-        if (this.user) {
-          this.userStore.setRouteAccess(newObj.database_id)
-        }
         /* load table */
         if (newObj.table_id) {
           this.cacheStore.setRouteTable(newObj.database_id, newObj.table_id)
@@ -346,43 +353,33 @@ export default {
     }
   },
   mounted () {
-    this.initEnvironment()
     if (this.$route.query && this.$route.query.q) {
       this.search = this.$route.query.q
     }
-    if (!this.user) {
+    if (!this.cacheUser) {
       return
     }
     this.setTheme()
+    this.setLocale()
     this.cacheStore.reloadMessages()
   },
   methods: {
-    errorCodeKey,
-    login () {
-      const redirect = ![undefined, '/', '/login'].includes(this.$router.currentRoute.path)
-      this.$router.push({ path: '/login', query: redirect ? { redirect: this.$router.currentRoute.path } : {} })
-    },
-    logout () {
-      this.$vuetify.theme.global.name = 'tuwThemeLight'
-      this.userStore.logout()
-      this.$router.push('/database')
-    },
     retrieve () {
       console.debug('performing fuzzy search')
       this.$router.push({ path: '/search', query: { q: this.search } })
     },
-    initEnvironment () {
-      if (this.token && !this.user) {
-        console.error('Something went wrong with loading the user: reset user cache')
-        this.userStore.logout()
-      }
+    setLocale () {
       if (!this.locale) {
-        this.userStore.setLocale('en')
+        this.cacheStore.setLocale('en')
+        return
       }
       this.$i18n.locale = this.locale
     },
     setTheme () {
-      switch (this.user.attributes.theme) {
+      if (!this.cacheUser?.theme) {
+        return
+      }
+      switch (this.cacheUser.theme) {
         case 'dark':
           this.$vuetify.theme.global.name = 'tuwThemeDark'
           break
@@ -396,10 +393,6 @@ export default {
           this.$vuetify.theme.global.name = 'tuwThemeDarkContrast'
           break
       }
-    },
-    setLocale (code) {
-      this.userStore.setLocale(code)
-      this.$i18n.locale = this.locale
     }
   }
 }
diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json
index 2e94f572ec68f7f3c595254ed5c9a5e14099e623..07ac0163ef086dd1915d90daf5cf7aabc59695d4 100644
--- a/dbrepo-ui/locales/en-US.json
+++ b/dbrepo-ui/locales/en-US.json
@@ -606,10 +606,10 @@
       },
       "status": {
         "title": "Status",
-        "public": "Public",
+        "public": "Visible",
         "data": "Data-only",
         "schema": "Schema-only",
-        "draft": "Draft"
+        "draft": "Hidden"
       },
       "resource": {
         "data": {
diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts
index 4b1833d8162e7e1494f4164fa90bb76e107f7635..b3da7bd98c657513e85c64cd51fac4c118d433b7 100644
--- a/dbrepo-ui/nuxt.config.ts
+++ b/dbrepo-ui/nuxt.config.ts
@@ -3,19 +3,26 @@ import vuetify from 'vite-plugin-vuetify'
 
 const proxy: any = {}
 
-// /* proxies the backend calls, >>NOT<< the frontend calls (clicking) */
-// if (process.env.NODE_ENV === 'development') {
-//   const api = 'http://localhost'
-//   proxy['/api'] = api
-//   proxy['/pid'] = {
-//     target: api + '/api',
-//     changeOrigin: true,
-//     pathRewrite: {
-//       '^/pid': '/pid'
-//     }
-//   }
-//   process.env.NUXT_PUBLIC_API_SERVER = api
-// }
+/* proxies the backend calls, >>NOT<< the frontend calls */
+if (process.env.NODE_ENV === 'development') {
+  const api = 'http://localhost'
+  proxy['/api'] = api
+  proxy['/pid'] = {
+    target: api + '/api',
+    changeOrigin: true,
+    pathRewrite: {
+      '^/pid': '/pid'
+    }
+  }
+  process.env.VERSION = 'bun-dev'
+  process.env.NUXT_PUBLIC_API_SERVER = api
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL = api + '/realms/dbrepo/protocol/openid-connect/auth'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI = api + ':3001'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL = api + '/realms/dbrepo/protocol/openid-connect/logout'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI = api + ':3001/auth/keycloak/callback'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL = api + '/realms/dbrepo/protocol/openid-connect/token'
+  process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL = api + '/realms/dbrepo/protocol/openid-connect/userinfo'
+}
 
 /**
  * https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering
@@ -107,11 +114,37 @@ export default defineNuxtConfig({
     port: 3001
   },
 
+  oidc: {
+    defaultProvider: 'keycloak',
+    providers: {
+      keycloak: {
+        audience: 'account',
+        authorizationUrl: '',
+        baseUrl: 'http://localhost/realms/dbrepo',
+        clientId: 'dbrepo-client',
+        clientSecret: 'MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG',
+        exposeAccessToken: true,
+        logoutRedirectUri: '',
+        logoutUrl: '',
+        optionalClaims: ['realm_access'],
+        redirectUri: 'http://localhost',
+        scope: ['openid', 'roles'],
+        tokenUrl: '',
+        userInfoUrl: ''
+      },
+    },
+    middleware: {
+      globalMiddlewareEnabled: false,
+      customLoginPage: false
+    },
+  },
+
   modules: [
-    '@artmizu/nuxt-prometheus',
+    ['@artmizu/nuxt-prometheus', {verbose: false}],
     '@nuxtjs/i18n',
     '@pinia/nuxt',
     '@pinia-plugin-persistedstate/nuxt',
+    'nuxt-oidc-auth',
     async (options, nuxt) => {
       nuxt.hooks.hook('vite:extendConfig', config => config.plugins.push(
         vuetify()
@@ -160,6 +193,8 @@ export default defineNuxtConfig({
     },
   },
 
-  devtools: {enabled: true},
-  compatibilityDate: '2024-07-24'
+  devtools: {
+    enabled: false
+  },
+  compatibilityDate: '2025-01-25'
 })
diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json
index a1354778200ebabb28a575e204e264e6bd155774..d7d4917e9f45f113156951746486755d91ae7bed 100644
--- a/dbrepo-ui/package.json
+++ b/dbrepo-ui/package.json
@@ -4,7 +4,7 @@
   "type": "module",
   "scripts": {
     "build": "nuxt build",
-    "dev": "VERSION=bun-dev NODE_ENV=development nuxt dev",
+    "dev": "NODE_ENV=development nuxt dev",
     "generate": "nuxt generate",
     "preview": "nuxt preview",
     "postinstall": "nuxt prepare",
@@ -28,6 +28,7 @@
     "merkle-json": "^2.6.0",
     "moment": "^2.30.1",
     "nuxt": "^3.10.3",
+    "nuxt-oidc-auth": "^1.0.0-beta.5",
     "parse-md": "^3.0.3",
     "pinia": "^2.1.7",
     "qs": "^6.11.2",
diff --git a/dbrepo-ui/pages/container/index.vue b/dbrepo-ui/pages/container/index.vue
index 360ce1543fdf086d60d568ed066ccca1f7c04537..20fed36801c24184664744ccf8b06eecba358c33 100644
--- a/dbrepo-ui/pages/container/index.vue
+++ b/dbrepo-ui/pages/container/index.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="loggedIn">
     <v-toolbar
       flat
       :title="$t('pages.container.title')">
@@ -11,6 +12,9 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import ContainerList from '@/components/container/ContainerList.vue'
 
@@ -25,19 +29,19 @@ export default {
       containers: []
     }
   },
-  computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-  },
   mounted () {
-    this.loading = true
-    const containerService = useContainerService();
-    containerService.findAll()
-      .then((containers) => {
-        this.containers = containers
-        this.loading = false
-      })
+    this.fetchContainers()
+  },
+  methods: {
+    fetchContainers () {
+      this.loading = true
+      const containerService = useContainerService();
+      containerService.findAll()
+        .then((containers) => {
+          this.containers = containers
+          this.loading = false
+        })
+    }
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue
index 6e1e35aabb3b2c150f532edf8c8fea5af610088c..025cc9c4c438523c876c346f6ccb219933a5362c 100644
--- a/dbrepo-ui/pages/database/[database_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/info.vue
@@ -1,26 +1,27 @@
 <template>
   <div
-    v-if="canViewSchema">
+    v-if="identifier || canViewInfo">
     <DatabaseToolbar />
     <v-window
       v-model="tab">
       <v-window-item value="1">
         <Summary
-          v-if="hasIdentifier"
+          v-if="identifier"
           :identifier="identifier" />
         <v-card
-          v-if="hasIdentifier"
+          v-if="identifier"
           variant="flat"
           rounded="0">
           <v-card-text>
             <Select
-              :identifiers="filteredIdentifiers"
+              :identifiers="identifiers"
               :identifier="identifier" />
           </v-card-text>
         </v-card>
         <v-divider
-          v-if="hasIdentifier" />
+          v-if="identifier" />
         <v-card
+          v-if="canViewInfo"
           :title="$t('pages.database.title')"
           variant="flat"
           rounded="0">
@@ -94,7 +95,7 @@
                 <div>
                   <UserBadge
                     :user="database.owner"
-                    :other-user="user" />
+                    :other-user="cacheUser" />
                 </div>
               </v-list-item>
               <v-list-item
@@ -104,7 +105,7 @@
                 <div>
                   <UserBadge
                     :user="database.contact"
-                    :other-user="user" />
+                    :other-user="cacheUser" />
                 </div>
               </v-list-item>
             </v-list>
@@ -163,13 +164,30 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&type=database&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
 import { sizeToHumanLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -197,7 +215,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -206,7 +223,7 @@ export default {
       return 0
     },
     description () {
-      if (!this.hasIdentifier) {
+      if (!this.identifier) {
         return ''
       }
       return this.database.identifier.description
@@ -218,46 +235,25 @@ export default {
       return this.$config.public.database.image.height
     },
     publisher () {
-      if (!this.hasIdentifier) {
+      if (!this.identifier) {
         return ''
       }
       return this.database.identifier.publisher
     },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
-    roles () {
-      return this.userStore.getRoles
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    identifiers () {
-      if (!this.database) {
-        return []
-      }
-      return this.database.identifiers
+    access () {
+      return this.cacheStore.getAccess
     },
-    filteredIdentifiers () {
-      if (!this.identifiers) {
+    identifiers () {
+      if (!this.database || !this.database.identifiers) {
         return []
       }
-      if (!this.user) {
-        return this.identifiers.filter(i => i.status === 'published')
-      }
-      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id)
-    },
-    identifier () {
-      if (this.pid) {
-        const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
-      }
-      return this.filteredIdentifiers[0]
-    },
-    access () {
-      return this.userStore.getAccess
+      return this.database.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
     pid () {
       return this.$route.query.pid
@@ -300,9 +296,6 @@ export default {
       const databaseService = useDatabaseService()
       return databaseService.databaseToOwner(this.database)
     },
-    hasIdentifier () {
-      return this.identifier
-    },
     accessDescription () {
       if (!this.access) {
         return
@@ -335,12 +328,19 @@ export default {
       }
       return this.database.preview_image
     },
-    canViewSchema () {
-      if (this.error) {
+    canViewInfo () {
+      if (!this.database) {
         return false
       }
-      return this.database
-    }
+      if (this.database.is_public || this.database.is_schema_public) {
+        return true
+      }
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
+    },
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
index a57b439b216ae4743fd4bda292dc53e5f7e05a69..505a7651232b071a03dd2b7ea481ff306e8dc3b4 100644
--- a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist
       type="database"
       :database="database" />
@@ -9,9 +9,8 @@
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -39,34 +38,53 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    database () {
-      return this.cacheStore.getDatabase
+    access () {
+      return this.cacheStore.getAccess
+    },
+    identifier () {
+      if (!this.database) {
+        return false
+      }
+      const filter = this.database.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    canPersistIdentifier () {
+      if (!this.database || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
index df675d262e8e116b0c4252d74fe6878681388acb..b66e8d706de8f4d87dd44baff8e7ded81aa7fffa 100644
--- a/dbrepo-ui/pages/database/[database_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier">
     <Persist
       type="database"
       :database="database" />
@@ -9,9 +9,8 @@
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -35,46 +34,40 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
-    hasIdentifier () {
-      if (this.database && 'identifier' in this.database && this.database.identifier) {
-        return 'id' in this.database.identifier
-      }
-      return false
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    access () {
+      return this.cacheStore.getAccess
     },
     isOwner () {
-      if (!this.database || !this.user) {
+      if (!this.database || !this.cacheUser) {
         return false
       }
-      return this.database.owner.username === this.user.username
+      return this.database.owner.id === this.cacheUser.uid
     },
-    canCreateIdentifier () {
-      if (!this.roles || this.hasIdentifier) {
+    canPersistIdentifier () {
+      if (!this.database || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier') && this.isOwner
-    },
-    canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.hasIdentifier && this.roles.includes('modify-identifier-metadata')
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue
index d0fb517daebc37d65c3d18f1faed9f631a0ecff0..8905ede1d2f88c8b2411f65655c4443827c23315 100644
--- a/dbrepo-ui/pages/database/[database_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/settings.vue
@@ -1,14 +1,13 @@
 <template>
   <div
-    v-if="canView">
+    v-if="canViewSettings">
     <DatabaseToolbar
       ref="toolbar" />
     <v-window
-      v-if="user"
       v-model="tab">
       <v-window-item>
         <v-card
-          v-if="isOwner && canModifyImage"
+          v-if="canModifyImage"
           variant="flat"
           rounded="0"
           :title="$t('pages.database.subpages.settings.title')"
@@ -89,7 +88,6 @@
         </v-card>
         <v-divider />
         <v-card
-          v-if="isOwner"
           variant="flat"
           rounded="0"
           :title="$t('pages.database.subpages.access.title')"
@@ -106,7 +104,7 @@
             </template>
             <template v-slot:item.action="{ item }">
               <v-btn
-                v-if="item && item.user && item.user.username !== user.username"
+                v-if="item && item.user && item.user.username !== cacheUser.username"
                 size="x-small"
                 variant="flat"
                 color="warning"
@@ -247,7 +245,6 @@
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import EditAccess from '@/components/dialogs/EditAccess.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -323,7 +320,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -335,34 +331,22 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    token () {
-      return this.userStore.getToken
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     uploadProgress () {
       return this.cacheStore.getUploadProgress
     },
-    isOwner () {
-      if (!this.database || !this.user) {
-        return false
-      }
-      if (this.database.owner.id === null || this.user.id === null) {
-        return false
-      }
-      return this.database.owner.id === this.user.id
-    },
     isSameOwner () {
-      if (!this.modifyOwner || !this.user) {
+      if (!this.modifyOwner || !this.cacheUser) {
         return false
       }
-      return this.modifyOwner.id === this.user.id
+      return this.modifyOwner.id === this.cacheUser.uid
     },
     isSameVisibility () {
       if (!this.modifyVisibility || !this.database) {
@@ -371,46 +355,47 @@ export default {
       return this.modifyVisibility.is_public === this.database.is_public && this.modifyVisibility.is_schema_public === this.database.is_schema_public
     },
     canModifyVisibility () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('modify-database-visibility')
     },
     canModifyOwnership () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('modify-database-owner')
     },
     canUpdateScheme () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('find-database')
     },
     canModifyAccess () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('update-database-access')
     },
     canCreateAccess () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('create-database-access')
     },
     canModifyImage () {
-      if (!this.isOwner) {
+      if (!this.roles) {
         return false
       }
       return this.roles.includes('modify-database-image')
     },
-    canView () {
-      if (this.error) {
+    canViewSettings () {
+      if (!this.database || !this.cacheUser || !this.access) {
         return false
       }
-      return this.database
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid
     },
     previewImage () {
       if (this.file) {
@@ -477,7 +462,7 @@ export default {
         .then((database) => {
           const toast = useToastInstance()
           toast.success(this.$t('success.database.visibility'))
-          this.cacheStore.setDatabase(database)
+          this.cacheStore.reloadDatabase()
         })
         .catch(() => {
           this.loading = false
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
index e9719cd0efe49369d3735ab7f9d5a0e2acd22070..682fc59b98fa61b0b3fb15af227960050e5d94cb 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="canViewSubsetData">
     <SubsetToolbar />
     <v-toolbar
       color="secondary"
@@ -17,7 +18,7 @@
       </v-toolbar-title>
       <v-spacer />
       <v-btn
-        v-if="canDownload"
+        v-if="canViewSubsetData"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-download' : null"
         variant="flat"
         :loading="downloadLoading"
@@ -96,27 +97,28 @@ export default {
     subset () {
       return this.cacheStore.getSubset
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     executionUTC () {
       if (!this.subset) {
         return null
       }
       return formatTimestampUTCLabel(this.subset.created)
     },
-    canDownload () {
-      if (!this.result_visibility || !this.subset.id) {
-        return false
-      }
-      return this.subset.id
-    },
-    result_visibility () {
+    canViewSubsetData () {
       if (!this.database || !this.subset) {
         return false
       }
       if (this.database.is_public) {
         return true
       }
-      return this.subset.owner.username === this.username
-    },
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
+    }
   },
   mounted () {
     this.loadSubset()
@@ -139,10 +141,6 @@ export default {
           this.loadingSubset = false
         })
     },
-    loadResult () {
-      if (this.subset) {
-      }
-    },
     download () {
       this.downloadLoading = true
       const queryService = useQueryService()
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
index f067fbadb4a190aff0843e289281971997426772..db5d45b4610de195f2a16d213eea60674c8dcf86 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
@@ -1,36 +1,29 @@
 <template>
-  <div>
+  <div
+    v-if="identifier || canViewInfo">
     <SubsetToolbar />
     <v-card
       variant="flat"
       rounded="0">
       <Summary
-        v-if="hasIdentifier"
+        v-if="identifier"
         :identifier="identifier" />
       <v-card-text
-        v-if="hasIdentifier">
+        v-if="identifier">
         <Select
           :identifiers="identifiers"
           :identifier="identifier" />
       </v-card-text>
     </v-card>
     <v-divider
-      v-if="subset && identifier" />
+      v-if="canViewInfo && identifier" />
     <v-card
+      v-if="canViewInfo"
       variant="flat"
       rounded="0"
       :title="$t('pages.subset.title')">
       <v-card-text>
         <v-list
-          v-if="!subset"
-          lines="two"
-          dense>
-          <v-skeleton-loader
-            type="list-item-three-line"
-            width="50%" />
-        </v-list>
-        <v-list
-          v-else-if="subset"
           lines="two"
           dense>
           <v-list-item
@@ -50,7 +43,9 @@
             v-if="subset.creator"
             :title="$t('pages.subset.creator.title')"
             density="compact">
-            <UserBadge :user="subset.creator" :other-user="user" />
+            <UserBadge
+              :user="subset.creator"
+              :other-user="cacheUser" />
           </v-list-item>
           <v-list-item
             :title="$t('pages.subset.query.title')"
@@ -86,13 +81,30 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id, subset_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&qid=${subset_id}&type=subset&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import Summary from '@/components/identifier/Summary.vue'
 import SubsetToolbar from '@/components/subset/SubsetToolbar.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -134,7 +146,6 @@ export default {
       downloadLoading: false,
       error: false,
       promises: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -145,35 +156,33 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
-    access () {
-      return this.userStore.getAccess
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     subset () {
       return this.cacheStore.getSubset
     },
-    user () {
-      return this.userStore.getUser
-    },
     identifiers () {
-      if (!this.database || !this.database.subsets || this.database.subsets.length === 0) {
+      if (!this.database || !this.database.subsets) {
         return []
       }
-      return this.database.subsets.filter(s => s.query_id === Number(this.$route.params.subset_id))
-    },
-    hasIdentifier () {
-      return this.identifiers.length > 0
+      return this.database.subsets.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
-    identifier () {
-      if (this.pid) {
-        const filter = this.identifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
+    canViewInfo () {
+      if (!this.database) {
+        return false
+      }
+      if (this.database.is_public || this.database.is_schema_public) {
+        return true
+      }
+      if (!this.access) {
+        return false
       }
-      return this.identifiers[0]
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     title () {
-      if (!this.hasIdentifier) {
+      if (!this.identifier) {
         return null
       }
       const enTitle = this.identifier.titles.filter(t => t.language).filter(t => t.language === 'en')
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
index b15ecb3292520979e550f68c7c16ef873638b124..78878a0015f61ea3dadf38258b747b20fa8e94d9 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist
       type="subset"
       :database="database" />
@@ -9,9 +9,8 @@
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -47,34 +46,56 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    subset () {
+      return this.cacheStore.getSubset
     },
-    database () {
-      return this.cacheStore.getDatabase
+    access () {
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    identifier () {
+      if (!this.subset) {
+        return false
+      }
+      const filter = this.subset.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
+    },
+    canPersistIdentifier () {
+      if (!this.subset || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.subset.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
index 07be66bc73911c9bd7580991ef2c71c6d36de5bc..88209f50188e473e306a826674051de883e83b3f 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
@@ -1,18 +1,17 @@
 <template>
   <div
-    v-if="canPersistQuery">
+    v-if="canPersistIdentifier">
     <Persist
       type="subset"
       :database="database"
-      :query="query" />
+      :query="subset" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
 </template>
 
 <script>
-import Persist from '~/components/identifier/Persist.vue'
-import { useUserStore } from '~/stores/user.js'
-import { useCacheStore } from '~/stores/cache.js'
+import Persist from '@/components/identifier/Persist.vue'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -21,8 +20,6 @@ export default {
   data () {
     return {
       loading: false,
-      loadingQuery: false,
-      query: null,
       isAuthorizationError: false,
       items: [
         {
@@ -47,51 +44,37 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
+    },
+    subset () {
+      return this.cacheStore.getSubset
+    },
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    canPersistQuery () {
-      if (this.loadingQuery || !this.query) {
+    canPersistIdentifier () {
+      if (!this.subset || !this.roles || !this.cacheUser || !this.access) {
+        return false
+      }
+      if (this.roles.includes('create-foreign-identifier')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
       const userService = useUserService()
-      return userService.hasReadAccess(this.access)
-    }
-  },
-  mounted () {
-    this.loadQuery()
-  },
-  methods: {
-    loadQuery () {
-      this.loadingQuery = true
-      return new Promise((resolve, reject) => {
-        const queryService = useQueryService()
-        queryService.findOne(this.$route.params.database_id, this.$route.params.subset_id)
-          .then((query) => {
-            this.query = query
-            resolve(query)
-          })
-          .catch((error) => {
-            if (error.response.status === 405) {
-              this.isAuthorizationError = true
-            }
-            reject(error)
-          })
-          .finally(() => {
-            this.loadingQuery = false
-          })
-      })
+      return userService.hasReadAccess(this.access) && this.subset.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
index 0fb591f9f8307018da13539491089c68c2a9ba16..c3d07bba1570ef6e116ff0bb5e18145104526175 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
@@ -7,7 +7,6 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
 import Builder from '@/components/subset/Builder.vue'
 import {useCacheStore} from '@/stores/cache.js'
 
@@ -36,28 +35,15 @@ export default {
           disabled: true
         }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+      return this.cacheStore.getAccess
     },
     canCreateSubset () {
       if (!this.database) {
@@ -66,7 +52,11 @@ export default {
       if (this.database.is_public) {
         return true
       }
-      return this.hasReadAccess
+      if (!this.access) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
index 2f68604881a0e222dbd280a5c54ff375ca8c0825..d98a8ba2afc6f26466c50e31acfc10ed0f32acd3 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
@@ -39,11 +39,21 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     canViewSchema () {
-      if (this.error) {
+      if (!this.database) {
+        return false
+      }
+      if (this.database.is_schema_public) {
+        return true
+      }
+      if (!this.access) {
         return false
       }
-      return this.database
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
index 07747ed0cb50cdd950ee24dece9ff3c5faf6de06..13ee3951c80fae3bb0a3f8391133b53aec57bf79 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
@@ -53,7 +53,6 @@
         class="ml-2 mr-2"
         @click.stop="pick" />
     </v-toolbar>
-    <TimeDrift />
     <v-card
       v-if="error"
       variant="flat">
@@ -81,6 +80,7 @@
         @close="pickVersion" />
     </v-dialog>
     <v-dialog
+      v-if="loggedIn"
       v-model="addTupleDialog"
       persistent
       max-width="640">
@@ -91,6 +91,7 @@
         @close="close" />
     </v-dialog>
     <v-dialog
+      v-if="loggedIn"
       v-model="editTupleDialog"
       persistent
       max-width="640">
@@ -104,12 +105,13 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import TableHistory from '@/components/table/TableHistory.vue'
-import TimeDrift from '@/components/TimeDrift.vue'
 import TableToolbar from '@/components/table/TableToolbar.vue'
 import { formatTimestamp } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import EditTuple from '@/components/dialogs/EditTuple.vue'
 import BlobDownload from '@/components/table/BlobDownload.vue'
@@ -121,8 +123,7 @@ export default {
     BlobDownload,
     EditTuple,
     TableHistory,
-    TableToolbar,
-    TimeDrift
+    TableToolbar
   },
   data () {
     return {
@@ -179,31 +180,24 @@ export default {
       ],
       headers: [],
       rows: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     table () {
       return this.cacheStore.getTable
     },
-    user () {
-      return this.userStore.getUser
+    roles () {
+      return this.cacheStore.getRoles
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     title () {
       return (this.version ? this.$t('toolbars.database.history') : this.$t('toolbars.database.current')) + ' ' + this.versionFormatted
@@ -229,15 +223,6 @@ export default {
       }
       return this.version.substring(0, 10) + 'T' + this.version.substring(11, 19) + 'Z'
     },
-    canModify () {
-      if (!this.user || !this.access || !this.table) {
-        return false
-      }
-      if (this.access.type === 'write_own' && this.table.owner.id === this.user.id) {
-        return true
-      }
-      return this.access.type === 'write_all'
-    },
     primaryKeyColumns () {
       if (!this.table) {
         return []
@@ -245,47 +230,45 @@ export default {
       return this.table.constraints.primary_key.map(pk => pk.column)
     },
     canViewTableData () {
-      if (this.error) {
-        return false
-      }
       if (!this.table) {
         return false
       }
       if (this.table.is_public) {
         return true
       }
-      if (!this.roles || !this.roles.includes('view-table-data')) {
+      if (!this.roles || !this.roles.includes('view-table-data') || !this.access) {
         return false
       }
-      return this.hasReadAccess
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     canAddTuple () {
       if (!this.roles) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data')
     },
     canSelectTuples () {
       if (!this.roles) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data')
     },
     canEditTuple () {
       if (!this.roles || this.selection === null || this.selection.length !== 1) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data')
     },
     canDeleteTuple () {
       if (!this.roles || this.selection === null || this.selection.length < 1) {
         return false
       }
       const userService = useUserService()
-      return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('delete-table-data')
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('delete-table-data')
     }
   },
   watch: {
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
index 4cf0057ea429438ca08282a63ac27f182f80baf0..efbcd6accf7d3d896769241a7de0d1325a30b3a4 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
@@ -30,7 +30,6 @@
 
 <script>
 import TableImport from '@/components/table/TableImport.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -69,19 +68,21 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    table () {
+      return this.cacheStore.getTable
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    table () {
-      return this.cacheStore.getTable
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    access () {
+      return this.cacheStore.getAccess
     },
     title () {
       if (!this.table) {
@@ -90,10 +91,11 @@ export default {
       return this.$t('pages.table.import.title') + ' ' + this.table.name
     },
     canInsertTableData () {
-      if (!this.roles) {
+      if (!this.table || !this.access || !this.cacheUser || !this.roles || !this.roles.includes('insert-table-data')) {
         return false
       }
-      return this.roles.includes('insert-table-data')
+      const userService = useUserService()
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
index 916c72b85052ce54c71d0bfa3cbe67708d606b0a..687358f0290177012dc89f36e23666d6dd6d48d0 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
@@ -1,15 +1,14 @@
 <template>
   <div
-    v-if="canViewSchema">
+    v-if="identifier || canViewInfo">
     <TableToolbar
       :selection="selection" />
     <v-card
+      v-if="identifier"
       variant="flat">
       <Summary
-        v-if="hasIdentifier"
         :identifier="identifier" />
-      <v-card-text
-        v-if="hasIdentifier">
+      <v-card-text>
         <Select
           :identifiers="identifiers"
           :identifier="identifier" />
@@ -18,6 +17,7 @@
     <v-divider
       v-if="identifier" />
     <v-card
+      v-if="canViewInfo"
       variant="flat"
       rounded="0"
       :title="$t('pages.table.title')">
@@ -64,7 +64,7 @@
             :title="$t('pages.table.owner.title')">
             <UserBadge
               :user="table.owner"
-              :other-user="user" />
+              :other-user="cacheUser" />
           </v-list-item>
         </v-list>
       </v-card-text>
@@ -118,12 +118,29 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id, table_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&tid=${table_id}&type=table&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
 import Select from '@/components/identifier/Select.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -165,7 +182,6 @@ export default {
       loading: false,
       exchange: null,
       queue: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -173,50 +189,47 @@ export default {
     pid () {
       return this.$route.query.pid
     },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     table () {
       return this.cacheStore.getTable
     },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     canRead () {
       if (this.database && this.database.is_public) {
         return true
       }
-      if (!this.user || !this.access) {
+      if (!this.access) {
         return false
       }
-      return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all'
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
-    canViewSchema () {
-      if (this.error) {
-        return false
-      }
+    canViewInfo () {
       if (!this.table) {
         return false
       }
-      if (this.table.is_schema_public || this.table.is_public) {
+      if (this.table.is_public || this.table.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     canWrite () {
-      if (!this.table || !this.user || !this.access) {
-        return false
-      }
-      return (this.access.type === 'write_own' && this.table.owned_by === this.user.id) || this.access.type === 'write_all'
+      const userService = useUserService()
+      return userService.hasWriteAccess(this.table, this.access, this.cacheUser)
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasDescription () {
       return this.table && this.table.description
@@ -228,31 +241,10 @@ export default {
       return this.roles.includes('insert-table-data')
     },
     identifiers () {
-      if (!this.table || !this.table.identifiers || this.table.identifiers.length === 0) {
-        return []
-      }
-      return this.table.identifiers
-    },
-    filteredIdentifiers () {
-      if (!this.identifiers) {
+      if (!this.table || !this.table.identifiers) {
         return []
       }
-      if (!this.user) {
-        return this.identifiers.filter(i => i.status === 'published')
-      }
-      return this.identifiers.filter(i => i.status === 'published' || i.owned_by === this.user.id)
-    },
-    identifier () {
-      if (this.pid) {
-        const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
-      }
-      return this.filteredIdentifiers[0]
-    },
-    hasIdentifier () {
-      return this.identifier
+      return this.table.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
     brokerExtraInfo () {
       return this.$config.public.broker.extra
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
index 663b2a5550d7875e1da0c3ed86fab1f24f359350..e2d16e8db44efb0f558fa2c42e1225fc9e6b8355 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist type="table" :database="database" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
@@ -8,7 +8,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -45,34 +44,56 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    table () {
+      return this.cacheStore.getTable
     },
-    database () {
-      return this.cacheStore.getDatabase
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    access () {
+      return this.cacheStore.getAccess
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    identifier () {
+      if (!this.table) {
+        return false
+      }
+      const filter = this.table.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
+    },
+    canPersistIdentifier () {
+      if (!this.table || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
index 250fedaa5d4676dc6c304d3d71aa9b3a23b21ffc..6c26187fa23ff0669bad399b57e3ab48b15ec061 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canPersistTable">
+    v-if="canPersistIdentifier">
     <Persist
       type="table"
       :database="database"
@@ -13,7 +13,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -48,29 +47,37 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     table () {
       return this.cacheStore.getTable
     },
-    canPersistTable () {
-      if (!this.table) {
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    canPersistIdentifier () {
+      if (!this.table || !this.roles || !this.cacheUser || !this.access) {
+        return false
+      }
+      if (this.roles.includes('create-foreign-identifier')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
       const userService = useUserService()
-      return userService.hasReadAccess(this.access)
+      return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
index 0c6a60e15b9c052656a61e9d71ec3fcd3d944cb2..ac48b40644823b9393b26608a0cfa5e56790d03a 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
@@ -120,9 +120,11 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -168,14 +170,10 @@ export default {
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
       dateColumns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -183,7 +181,13 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
+    roles () {
+      return this.cacheStore.getRoles
     },
     hasReadAccess () {
       if (!this.access) {
@@ -191,29 +195,24 @@ export default {
       }
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     canViewSchema () {
-      if (this.error) {
-        return false
-      }
       if (!this.table) {
         return false
       }
       if (this.table.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     primaryKeysColumns () {
       return this.table.constraints.primary_key.map(pk => pk.column.internal_name).join(', ')
     },
     canAssignSemanticInformation () {
-      if (!this.user) {
+      if (!this.cacheUser || !this.roles) {
         return false
       }
       if (this.roles.includes('modify-foreign-table-column-semantics')) {
@@ -222,7 +221,7 @@ export default {
       if (!this.access) {
         return false
       }
-      return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.username === this.user.username)
+      return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.id === this.cacheUser.uid)
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
index f9530711363fb38884ac05dcaba3d28e1b6ee82a..0f0a8feab62a7fb065c3ecb6af6b63b83a9884be 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
@@ -3,7 +3,6 @@
     v-if="canUpdateTable">
     <TableToolbar />
     <v-window
-      v-if="user"
       v-model="tab">
       <v-window-item>
         <v-form
@@ -23,9 +22,6 @@
                   <v-textarea
                     v-model="modify.description"
                     rows="2"
-                    :rules="[
-                      v => max(v, 180) || ($t('validation.max-length') + 180),
-                    ]"
                     clearable
                     counter="180"
                     persistent-counter
@@ -116,7 +112,6 @@
 
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import { max } from '@/utils'
 
@@ -127,7 +122,7 @@ export default {
   data () {
     return {
       tab: 0,
-      valid: false,
+      valid: true,
       loading: false,
       modify: {
         description: null,
@@ -175,14 +170,10 @@ export default {
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
       dateColumns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -190,47 +181,39 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     isChange () {
       if (!this.table) {
         return false
       }
-      if (this.table.is_public !== this.modify.is_public) {
+      if (this.table.is_public !== this.modify.is_public || this.table.is_schema_public !== this.modify.is_schema_public) {
         return true
       }
-      return this.table.is_schema_public !== this.modify.is_schema_public
+      return this.table.description !== this.modify.description
     },
     canUpdateTable () {
-      if (!this.roles || !this.user || !this.table) {
-        return false
-      }
-      return this.roles.includes('update-table') && this.table.owner.id === this.user.id
-    },
-    canModifyVisibility () {
-      if (!this.roles || !this.user || !this.table) {
+      if (!this.cacheUser || !this.table || !this.access || !this.roles || !this.roles.includes('update-table')) {
         return false
       }
-      return this.roles.includes('update-table') && this.table.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid
     },
     canDropTable () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.cacheUser) {
         return false
       }
       if (this.roles.includes('delete-foreign-table')) {
         return true
       }
       const tableService = useTableService()
-      return tableService.isOwner(this.table, this.user) && this.roles.includes('delete-table') && this.table.identifiers.length === 0
+      return tableService.isOwner(this.table, this.cacheUser) && this.roles.includes('delete-table') && this.table.identifiers.length === 0
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
index df74cc6e7046e90f6e5e9844769a2e1e8f45e372..24aed7f2ffc6b77edfae4a90e1c4dc7607f97955 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
@@ -92,9 +92,6 @@
                       <v-textarea
                         v-model="tableCreate.description"
                         rows="2"
-                        :rules="[
-                          v => (!!v || v.length <= 180) || ($t('validation.max-length') + 180),
-                        ]"
                         clearable
                         counter="180"
                         persistent-counter
@@ -219,10 +216,9 @@
   </div>
 </template>
 
-<script>
+  <script>
 import TableSchema from '@/components/table/TableSchema.vue'
 import { notEmpty } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -304,7 +300,6 @@ export default {
       loading: false,
       url: null,
       columns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -316,15 +311,12 @@ export default {
     this.tableCreate.is_schema_public = this.database.is_schema_public
   },
   computed: {
-    user() {
-      return this.userStore.getUser
-    },
-    roles() {
-      return this.userStore.getRoles
-    },
     database() {
       return this.cacheStore.getDatabase
     },
+    roles () {
+      return this.cacheStore.getRoles
+    },
     generatedTableName() {
       if (!this.tableCreate.name) {
         return null
diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
index c900ba31aa104dcc1ce5e3250dd0bb5a2b92f6fa..804ae03c15072719f7612fd46eeca80d45b1a2b8 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
@@ -70,9 +70,6 @@
                     <v-textarea
                       v-model="tableCreate.description"
                       rows="2"
-                      :rules="[
-                        v => (!v || v.length <= 180) || $t('validation.max-length') + 180
-                      ]"
                       clearable
                       counter="180"
                       persistent-counter
@@ -188,7 +185,6 @@
 <script>
 import TableSchema from '@/components/table/TableSchema.vue'
 import { notEmpty } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -247,7 +243,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -259,15 +254,12 @@ export default {
       const tableService = useTableService()
       return tableService.tableNameToInternalName(this.tableCreate.name)
     },
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
+    roles () {
+      return this.cacheStore.getRoles
+    },
     canCreateTable () {
       if (!this.roles) {
         return false
diff --git a/dbrepo-ui/pages/database/[database_id]/table/index.vue b/dbrepo-ui/pages/database/[database_id]/table/index.vue
index ae3e3c13f1b173b62514e1ee8887fd648e3f65a1..c2a2b76206918a0882c7e041aa3f38fb19ccfe12 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/index.vue
@@ -48,11 +48,18 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     canViewSchema () {
-      if (this.error) {
+      if (!this.database) {
         return false
       }
-      return this.database
+      if (this.database.is_schema_public) {
+        return true
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
index 54c54dad00d4764383c8d38e979870391680d563..f732661f369710b4637f01952f5fab930e9e4812 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
@@ -22,7 +22,6 @@
         :loading="loadingData"
         @click="reload" />
     </v-toolbar>
-    <TimeDrift />
     <v-card tile>
       <QueryResults
         id="query-results"
@@ -35,14 +34,11 @@
 </template>
 
 <script>
-import TimeDrift from '@/components/TimeDrift.vue'
 import QueryResults from '@/components/subset/Results.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
-    QueryResults,
-    TimeDrift
+    QueryResults
   },
   data () {
     return {
@@ -70,14 +66,10 @@ export default {
           disabled: true
         }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -85,13 +77,10 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' ||  this.access.type === 'write_own' ||  this.access.type === 'write_all'
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     canReadData () {
       if (!this.view) {
@@ -100,10 +89,11 @@ export default {
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.view.owner.id === this.user.id || this.hasReadAccess
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
   },
   mounted () {
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
index c9865a1b4abbefd3bd07361b7c6a5a5ff86b0834..3c0c40e33ce7546e351ea3252a051a0ebb56049e 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
@@ -1,25 +1,25 @@
 <template>
   <div
-    v-if="canViewView">
+    v-if="identifier || canViewInfo">
     <ViewToolbar />
     <v-window
       v-model="tab">
-      <v-window-item
-        v-if="view">
+      <v-window-item>
         <v-card variant="flat">
           <Summary
-            v-if="hasIdentifier"
+            v-if="identifier"
             :identifier="identifier" />
           <v-card-text
-            v-if="hasIdentifier">
+            v-if="identifier">
             <Select
               :identifiers="identifiers"
               :identifier="identifier" />
           </v-card-text>
         </v-card>
         <v-divider
-          v-if="hasIdentifier" />
+          v-if="identifier" />
         <v-card
+          v-if="canViewInfo"
           :title="$t('pages.view.title')"
           variant="flat">
           <v-card-text>
@@ -39,7 +39,7 @@
                 <UserBadge
                   v-if="view"
                   :user="view.owner"
-                  :other-user="user" />
+                  :other-user="cacheUser" />
                 <v-skeleton-loader
                   v-else
                   type="subtitle"
@@ -59,13 +59,30 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const config = useRuntimeConfig()
+const { pid } = useRoute().query
+const { database_id, view_id } = useRoute().params
+const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&vid=${view_id}&type=view&status=published`)
+
+if (data.value && data.value.length > 0) {
+  const identifierService = useIdentifierService()
+  useServerHead(identifierService.identifiersToServerHead(data.value))
+  useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value))
+}
+const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null)
+
+const cacheStore = useCacheStore()
+cacheStore.setIdentifier(identifier)
+</script>
 <script>
 import ViewToolbar from '@/components/view/ViewToolbar.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -103,55 +120,30 @@ export default {
         }
       ],
       error: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     view () {
       return this.cacheStore.getView
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    roles () {
+      return this.cacheStore.getRoles
     },
-    identifiers () {
-      if (!this.view) {
-        return []
-      }
-      return this.view.identifiers
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    filteredIdentifiers () {
-      if (!this.identifiers) {
+    identifiers () {
+      if (!this.view || !this.view.identifiers) {
         return []
       }
-      if (!this.user) {
-        return this.identifiers.filter(i => i.status === 'published')
-      }
-      return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id)
-    },
-    identifier () {
-      if (this.pid) {
-        const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid))
-        if (filter.length > 0) {
-          return filter[0]
-        }
-      }
-      return this.filteredIdentifiers[0]
+      return this.view.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id))
     },
     views () {
       if (!this.database) {
@@ -162,9 +154,6 @@ export default {
     pid () {
       return this.$route.query.pid
     },
-    hasIdentifier () {
-      return this.identifier
-    },
     creator () {
       if (!this.view) {
         return null
@@ -172,17 +161,18 @@ export default {
       const userService = useUserService()
       return userService.userToFullName(this.view.creator)
     },
-    canViewView () {
+    canViewInfo () {
       if (!this.view) {
         return false
       }
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   },
   methods: {
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
index 8c1f24c2a166150bd1dc3903dfa984c435815f9b..540bbbdb5e454c725c6d5b9dc6a1da6498e5f8bc 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canCreateIdentifier || canUpdateIdentifier">
+    v-if="canPersistIdentifier || canUpdateIdentifier">
     <Persist
       type="view"
       :database="database" />
@@ -10,7 +10,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -47,34 +46,56 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
+    database () {
+      return this.cacheStore.getDatabase
+    },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    user () {
-      return this.userStore.getUser
+    view () {
+      return this.cacheStore.getView
     },
-    database () {
-      return this.cacheStore.getDatabase
+    access () {
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
-    canCreateIdentifier () {
-      if (!this.roles) {
+    identifier () {
+      if (!this.view) {
+        return false
+      }
+      const filter = this.view.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id))
+      return filter.length === 1 ? filter[0] : null
+    },
+    canPersistIdentifier () {
+      if (!this.view || !this.roles || !this.cacheUser || !this.access) {
         return false
       }
       if (this.roles.includes('create-foreign-identifier')) {
         return true
       }
-      return this.roles.includes('create-identifier')
+      if (!this.roles.includes('create-identifier')) {
+        return false
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid
     },
     canUpdateIdentifier () {
-      if (!this.roles) {
+      if (!this.identifier || !this.roles) {
+        return false
+      }
+      if (this.roles.includes('modify-identifier-metadata')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
-      return this.roles.includes('modify-identifier-metadata')
+      return this.identifier.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
index b76d076645e05ef7123215c578d20b489924d523..ed8067d21327f2e0a069733fb9873b7912a5a32e 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canPersistView">
+    v-if="canPersistIdentifier">
     <Persist
       type="view"
       :database="database"
@@ -11,7 +11,6 @@
 
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -45,32 +44,37 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
+    },
     view () {
-      if (!this.database) {
-        return null
-      }
-      return this.database.views.filter(v => v.id === Number(this.$route.params.view_id))[0]
+      return this.cacheStore.getView
     },
-    access () {
-      return this.userStore.getAccess
+    roles () {
+      return this.cacheStore.getRoles
     },
-    canPersistView () {
-      if (!this.view) {
+    canPersistIdentifier () {
+      if (!this.view || !this.roles || !this.cacheUser || !this.access) {
+        return false
+      }
+      if (this.roles.includes('create-foreign-identifier')) {
+        return true
+      }
+      if (!this.roles.includes('create-identifier')) {
         return false
       }
       const userService = useUserService()
-      return userService.hasReadAccess(this.access)
+      return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
index 477654f656c9dbc5361315d323b8cc638add6ca9..5b35faf3a5250c712a6e9b7f442a6e779863b42c 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
@@ -53,7 +53,6 @@
 
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -95,14 +94,10 @@ export default {
         { value: 'is_null_allowed', title: this.$t('pages.table.subpages.schema.nullable.title') },
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -110,13 +105,13 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+    roles () {
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     canViewSchema () {
       if (!this.view) {
@@ -125,13 +120,11 @@ export default {
       if (this.view.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.access) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
-    },
-    roles () {
-      return this.userStore.getRoles
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
index 18d73d05768d1a45b36eed9a58ea7841235554b3..d027a4347b5300025f83d23adba52d78278a443f 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
@@ -92,7 +92,6 @@
 
 <script>
 import ViewToolbar from '@/components/view/ViewToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -148,14 +147,10 @@ export default {
         { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') },
       ],
       dateColumns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -163,16 +158,13 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
-    },
-    hasReadAccess () {
-      if (!this.access) {
-        return false
-      }
-      return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
+    },
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     isChange () {
       if (!this.view) {
@@ -184,22 +176,23 @@ export default {
       return this.view.is_schema_public !== this.modify.is_schema_public
     },
     canUpdateVisibility () {
-      if (!this.roles || !this.user || !this.view) {
+      if (!this.roles || !this.cacheUser || !this.view) {
         return false
       }
-      return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.user.id
+      return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.cacheUser.uid
     },
     canDeleteView () {
-      if (!this.roles || !this.user || !this.view) {
+      if (!this.roles || !this.cacheUser || !this.view) {
         return false
       }
-      return this.roles.includes('delete-database-view') && this.view.owner.id === this.user.id
+      return this.roles.includes('delete-database-view') && this.view.owner.id === this.cacheUser.uid
     },
     canViewSettings () {
-      if (!this.user || !this.view) {
+      if (!this.view || !this.access || !this.cacheUser) {
         return false
       }
-      return this.view.owner.id === this.user.id
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/pages/database/[database_id]/view/create.vue b/dbrepo-ui/pages/database/[database_id]/view/create.vue
index 47b56cfbad81968d056d028cc48758d250efc612..a834bdb5c90340d247dbb3df880acbec8dc4a08f 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/create.vue
@@ -8,7 +8,7 @@
 
 <script>
 import Builder from '@/components/subset/Builder.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -35,21 +35,22 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    access () {
+      return this.cacheStore.getAccess
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     canCreateView () {
-      if (!this.roles) {
+      if (!this.roles || !this.roles.includes('create-database-view')) {
         return false
       }
-      return this.roles.includes('create-database-view')
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/index.vue b/dbrepo-ui/pages/database/[database_id]/view/index.vue
index 64f777dce3f905f19d2ff8f16e5e4b3de80fd277..b2a2c17a1afe0553777e21e593b8865bfb63efc9 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/index.vue
@@ -48,11 +48,18 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    access () {
+      return this.cacheStore.getAccess
+    },
     canViewSchema () {
-      if (this.error) {
+      if (!this.database) {
         return false
       }
-      return this.database
+      if (this.database.is_schema_public) {
+        return true
+      }
+      const userService = useUserService()
+      return userService.hasReadAccess(this.access)
     }
   }
 }
diff --git a/dbrepo-ui/pages/index.vue b/dbrepo-ui/pages/index.vue
index 1c30c25e5c7e9edfd52861ca568c492ce39f13a7..9e5e20186dcdd58ab66662b5aca827e2682df121 100644
--- a/dbrepo-ui/pages/index.vue
+++ b/dbrepo-ui/pages/index.vue
@@ -30,7 +30,7 @@
 <script>
 import DatabaseList from '@/components/database/DatabaseList.vue'
 import DatabaseCreate from '@/components/database/DatabaseCreate.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -42,12 +42,12 @@ export default {
       loading: true,
       dialog: null,
       databases: [],
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
     canCreateDatabase () {
       if (!this.roles) {
@@ -57,17 +57,20 @@ export default {
     }
   },
   mounted () {
-    this.loading = true
-    const databaseService = useDatabaseService();
-    databaseService.findAll()
-      .then((databases) => {
-        this.databases = databases
-        this.loading = false
-      })
+    this.fetchDatabases()
   },
   methods: {
     closed () {
       this.dialog = false
+    },
+    fetchDatabases () {
+      this.loading = true
+      const databaseService = useDatabaseService()
+      databaseService.findAll()
+        .then((databases) => {
+          this.databases = databases
+          this.loading = false
+        })
     }
   }
 }
diff --git a/dbrepo-ui/pages/login.vue b/dbrepo-ui/pages/login.vue
deleted file mode 100644
index 532a221c4823cfd8be39fd53e94c34426311260a..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/login.vue
+++ /dev/null
@@ -1,160 +0,0 @@
-<template>
-  <div>
-    <v-toolbar
-      v-if="!user"
-      variant="flat"
-      :title="$t('pages.login.name')">
-    </v-toolbar>
-    <v-card
-      rounded="0"
-      variant="flat">
-      <v-card-text>
-        <v-form
-          v-if="!user"
-          ref="form"
-          v-model="valid"
-          @submit.prevent="submit">
-          <v-row
-            dense>
-            <v-col
-              md="8">
-              <v-text-field
-                v-model="username"
-                autocomplete="off"
-                autofocus
-                required
-                name="username"
-                persistent-hint
-                :rules="[v => !!v || $t('validation.required')]"
-                :label="$t('pages.login.username.label')"
-                :hint="$t('pages.login.username.hint')"/>
-            </v-col>
-          </v-row>
-          <v-row
-            dense>
-            <v-col
-              md="8">
-              <v-text-field
-                v-model="password"
-                autocomplete="off"
-                type="password"
-                required
-                name="password"
-                persistent-hint
-                :rules="[v => !!v || $t('validation.required')]"
-                :label="$t('pages.login.password.label')"
-                :hint="$t('pages.login.password.hint')"/>
-            </v-col>
-          </v-row>
-          <v-row>
-            <v-col
-              md="8">
-              <v-btn
-                id="login"
-                class="mb-2"
-                :disabled="!valid"
-                color="primary"
-                variant="flat"
-                type="submit"
-                name="submit"
-                :loading="loading"
-                :text="$t('pages.login.submit.label')"
-                @click="login"/>
-            </v-col>
-          </v-row>
-        </v-form>
-      </v-card-text>
-      <v-card-actions>
-        <v-spacer/>
-        <v-btn
-          v-for="(link, i) in loginLinks"
-          :key="`li-${i}`"
-          variant="plain"
-          size="small"
-          :text="link.text"
-          :href="link.href"/>
-      </v-card-actions>
-    </v-card>
-  </div>
-</template>
-
-<script>
-import {useUserStore} from '@/stores/user.js'
-
-export default {
-  data() {
-    return {
-      loading: false,
-      valid: false,
-      username: null,
-      password: null,
-      userStore: useUserStore()
-    }
-  },
-  computed: {
-    user() {
-      return this.userStore.getUser
-    },
-    loginLinks() {
-      if (!this.$config.public.links) {
-        return []
-      }
-      return Object.keys(this.$config.public.links).map(key => {
-        return this.$config.public.links[key]
-      })
-    }
-  },
-  methods: {
-    submit() {
-      this.$refs.form.validate()
-    },
-    login() {
-      this.loading = true
-      const userService = useUserService()
-      userService.obtainToken(this.username, this.password)
-        .then((data) => {
-          const userId = userService.tokenToUserId(data.access_token)
-          userService.findOne(userId)
-            .then((user) => {
-              const toast = useToastInstance()
-              toast.success(this.$t('success.user.login', { username : user.username }))
-              switch (user.attributes.theme) {
-                case 'dark':
-                  this.$vuetify.theme.global.name = 'tuwThemeDark'
-                  break
-                case 'light':
-                  this.$vuetify.theme.global.name = 'tuwThemeLight'
-                  break
-                case 'light-contrast':
-                  this.$vuetify.theme.global.name = 'tuwThemeLightContrast'
-                  break
-                case 'dark-contrast':
-                  this.$vuetify.theme.global.name = 'tuwThemeDarkContrast'
-                  break
-              }
-              this.userStore.setUser(user)
-              this.$router.push('/database')
-            })
-            .catch(({code}) => {
-              const toast = useToastInstance()
-              if (typeof code !== 'string') {
-                return
-              }
-              toast.error(this.$t(code))
-            })
-        })
-        .catch(({code}) => {
-          this.loading = false
-          const toast = useToastInstance()
-          if (typeof code !== 'string') {
-            return
-          }
-          toast.error(this.$t(code))
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/search.vue b/dbrepo-ui/pages/search.vue
index 15475b212bc724e0e55d9f0765461990e574618e..507f81b731407a3059e61f7956368d25481de9a0 100644
--- a/dbrepo-ui/pages/search.vue
+++ b/dbrepo-ui/pages/search.vue
@@ -65,7 +65,6 @@
 
 <script>
 import AdvancedSearch from '@/components/search/AdvancedSearch.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -75,14 +74,10 @@ export default {
     return {
       results: [],
       type: 'database',
-      loading: false,
-      userStore: useUserStore()
+      loading: false
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     q () {
       if (!this.$route.query || !this.$route.query.q) {
         return null
@@ -92,12 +87,6 @@ export default {
     header () {
       return `${this.results.length} ${this.results.length !== 1 ? this.$t('toolbars.search.results') : this.$t('toolbars.search.result')}`
     },
-    canCreateDatabase () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('create-database')
-    },
     isDatabaseSearch () {
       return this.type === 'database'
     }
diff --git a/dbrepo-ui/pages/semantic/index.vue b/dbrepo-ui/pages/semantic/index.vue
deleted file mode 100644
index db555b4c0d4778401e6988015b1064cc8bd0c82e..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/semantic/index.vue
+++ /dev/null
@@ -1,194 +0,0 @@
-<template>
-  <div v-if="canListOntologies">
-    <v-toolbar flat>
-      <v-toolbar-title>
-        {{ $t('pages.semantics.title') }}
-      </v-toolbar-title>
-      <v-spacer />
-      <v-btn
-        v-if="canListOntologies"
-        to="/semantic/ontology"
-        variant="flat"
-        :text="ontologies.length + ' ' + $t('toolbars.semantic.ontologies.text')"
-        color="secondary" />
-      <template v-slot:extension>
-        <v-tabs
-          v-model="tab"
-          color="primary">
-          <v-tab>
-            {{ $t('toolbars.semantic.ontologies.concepts') }}
-          </v-tab>
-          <v-tab>
-            {{ $t('toolbars.semantic.ontologies.units') }}
-          </v-tab>
-        </v-tabs>
-      </template>
-    </v-toolbar>
-    <v-card flat>
-      <v-card-text>
-        <v-data-table
-          :headers="headers"
-          :items="rows"
-          :options.sync="options"
-          :server-items-length="total"
-          :footer-props="footerProps"
-          :items-per-page-options="footerProps.itemsPerPageOptions">
-          <template v-slot:item.uri="{ item }">
-            <a :href="item.uri"
-               target="_blank">
-              {{ item.uri }}
-            </a>
-          </template>
-          <template v-slot:item.action="{ item }">
-            <v-btn
-              small
-              :disabled="disabled(item)"
-              :text="$t('pages.semantics.usages.text')"
-              @click="view(item)" />
-          </template>
-        </v-data-table>
-      </v-card-text>
-    </v-card>
-    <v-dialog
-      v-model="viewSemanticEntityDialog"
-      max-width="640">
-      <ViewSemanticEntity
-        :mode="mode"
-        :entity="entity"
-        @close="close" />
-    </v-dialog>
-    <v-breadcrumbs
-      :items="items"
-      class="pa-0 mt-2" />
-  </div>
-</template>
-
-<script>
-import ViewSemanticEntity from '@/components/dialogs/ViewSemanticEntity.vue'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  components: {
-    ViewSemanticEntity
-  },
-  data () {
-    return {
-      loadingConcepts: false,
-      loadingUnits: false,
-      entity: null,
-      viewSemanticEntityDialog: false,
-      headers: [
-        { text: 'URI', value: 'uri' },
-        { text: 'Name', value: 'name' },
-        { text: 'Description', value: 'description' },
-        { text: 'Usages', value: 'usages' },
-        { text: null, value: 'action' }
-      ],
-      options: {
-        page: 1,
-        itemsPerPage: 10
-      },
-      total: -1,
-      footerProps: {
-        itemsPerPageOptions: [10, 25, 50, 100]
-      },
-      tab: 0,
-      tabs: [
-        'concepts', 'units'
-      ],
-      concepts: [],
-      units: [],
-      createOntologyDialog: false,
-      items: [
-        {
-          title: `${this.$t('navigation.semantics')}`,
-          to: '/semantic'
-        }
-      ],
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    },
-    rows () {
-      return this.tab === 0 ? this.concepts : this.units
-    },
-    mode () {
-      return this.tab === 0 ? 'concept' : 'unit'
-    },
-    canListOntologies () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-ontologies')
-    }
-  },
-  mounted () {
-    this.loadUnits()
-    this.loadConcepts()
-  },
-  methods: {
-    loadConcepts () {
-      this.loadingConcepts = true
-      const conceptService = useConceptService()
-      conceptService.findAll()
-        .then((concepts) => {
-          concepts = concepts.map((column) => {
-            column.usages = column.columns.length
-            return column
-          })
-          this.concepts = concepts
-        })
-        .catch(() => {
-          this.loadingConcepts = false
-        })
-        .finally(() => {
-          this.loadingConcepts = false
-        })
-    },
-    loadUnits () {
-      this.loadingUnits = true
-      const unitService = useUnitService()
-      unitService.findAll()
-        .then((units) => {
-          units = units.map((unit) => {
-            unit.usages = unit.columns.length
-            return unit
-          })
-          this.units = units
-        })
-        .catch(() => {
-          this.loadingUnits = false
-        })
-        .finally(() => {
-          this.loadingUnits = false
-        })
-    },
-    disabled (item) {
-      return !item.usages || this.usages === 0
-    },
-    view (entity) {
-      this.entity = entity
-      this.viewSemanticEntityDialog = true
-    },
-    close (event) {
-      if (this.mode === 'unit') {
-        this.loadUnits()
-      } else if (this.mode === 'concept') {
-        this.loadConcepts()
-      }
-      this.viewSemanticEntityDialog = false
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue
deleted file mode 100644
index 14749460c931c70c8430a28e51a7aa3c13d26ed1..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue
+++ /dev/null
@@ -1,273 +0,0 @@
-<template>
-  <div
-    v-if="canListOntologies">
-    <v-toolbar flat>
-      <v-toolbar-title>
-        <v-btn
-          id="back-btn"
-          plain
-          class="mr-2"
-          to="/semantic/ontology">
-          <v-icon left>mdi-arrow-left</v-icon>
-        </v-btn>
-      </v-toolbar-title>
-      <v-toolbar-title>
-        <v-skeleton-loader
-          v-if="loading"
-          type="text"
-          class="skeleton-small" />
-        <span v-if="!loading">
-          Ontology
-          <a
-            v-if="ontology"
-            :href="ontology.uri"
-            target="_blank">
-            {{ ontology.uri }}
-          </a>
-        </span>
-      </v-toolbar-title>
-      <v-spacer />
-      <v-toolbar-title>
-        <v-btn
-          v-if="canDeleteOntology"
-          :loading="loadingDelete"
-          color="error"
-          @click="deleteOntology">
-          Delete Ontology
-        </v-btn>
-      </v-toolbar-title>
-    </v-toolbar>
-    <v-form ref="form" v-model="valid" autocomplete="off" @submit.prevent="submit">
-      <v-card v-if="ontology" variant="flat">
-        <v-card-text>
-          <v-row dense>
-            <v-col cols="6">
-              <v-text-field
-                id="prefix"
-                v-model="ontologyChangeDto.prefix"
-                name="prefix"
-                label="Prefix *"
-                hint="Only lowercase alphanumeric letters, max. 8"
-                autofocus
-                :rules="[
-                  v => notEmpty(v) || $t('validation.required'),
-                  v => validPrefix(v) || $t('validation.prefix.pattern'),
-                  v => validPrefixLength(v,1,8) || $t('validation.prefix.length'),
-                  v => validPrefixNotExists(v) || $t('validation.prefix.exists')
-                ]"
-                required />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col cols="6">
-              <v-text-field
-                id="uri"
-                v-model="ontologyChangeDto.uri"
-                name="uri"
-                label="URI *"
-                :rules="[
-                  v => notEmpty(v) || $t('validation.required'),
-                  v => validUri(v) || $t('validation.uri.pattern'),
-                  v => validUriNotExists(v) || $t('validation.uri.exists')
-                ]"
-                required />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col cols="6">
-              <v-text-field
-                id="sparql-endpoint"
-                v-model="ontologyChangeDto.sparql_endpoint"
-                name="sparql-endpoint"
-                label="SPARQL Endpoint"
-                :rules="[
-                  v => validUriOptional(v) || $t('validation.uri.pattern')
-                ]" />
-            </v-col>
-          </v-row>
-        </v-card-text>
-        <v-card-actions>
-          <v-btn
-            id="createDB"
-            class="mb-2 ml-2"
-            :disabled="!valid || loading"
-            color="primary"
-            type="submit"
-            :loading="loading"
-            @click="save">
-            Update
-          </v-btn>
-        </v-card-actions>
-      </v-card>
-    </v-form>
-    <v-breadcrumbs :items="items" class="pa-0 mt-2" />
-  </div>
-</template>
-
-<script>
-import { notEmpty } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  data () {
-    return {
-      loading: false,
-      loadingDelete: false,
-      ontology: null,
-      ontologyChangeDto: {
-        uri: null,
-        prefix: null,
-        sparql_endpoint: null
-      },
-      valid: false,
-      createOntologyDialog: false,
-      items: [
-        { text: `${this.$t('layout.semantics')}`, to: '/semantic', activeClass: '' },
-        { text: `${this.$t('layout.ontologies')}`, to: '/semantic/ontology', activeClass: '' },
-        { text: `${this.$route.params.ontology_id}`, to: `/semantic/ontology/${this.$route.params.ontology_id}`, activeClass: '' }
-      ],
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    },
-    canListOntologies () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-ontologies')
-    },
-    canDeleteOntology () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('delete-ontology')
-    }
-  },
-  mounted () {
-    this.loadOntology()
-  },
-  methods: {
-    loadOntology () {
-      this.loading = true
-      const ontologyService = useOntologyService()
-      ontologyService.findOne(this.$route.params.ontology_id)
-        .then((ontology) => {
-          this.ontology = ontology
-          this.ontologyChangeDto = Object.assign({}, ontology)
-        })
-        .catch(() => {
-          this.loading = false
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    },
-    deleteOntology () {
-      this.loadingDelete = true
-      const ontologyService = useOntologyService()
-      ontologyService.remove(this.$route.params.ontology_id)
-        .then(async () => {
-          // await this.$store.dispatch('reloadOntologies')
-          await this.$router.push('/semantic/ontology')
-        })
-        .catch(() => {
-          this.loadingDelete = false
-        })
-        .finally(() => {
-          this.loadingDelete = false
-        })
-    },
-    save () {
-      this.loading = true
-      const payload = {
-        uri: this.ontologyChangeDto.uri,
-        prefix: this.ontologyChangeDto.prefix,
-        sparql_endpoint: this.ontologyChangeDto.sparql_endpoint
-      }
-      const ontologyService = useOntologyService()
-      ontologyService.update(this.$route.params.ontology_id, payload)
-        .then(() => {
-          this.loadOntology()
-          // this.$store.dispatch('reloadOntologies')
-          const toast = useToastInstance()
-          toast.success('Successfully update ontology!')
-        })
-        .catch(() => {
-          this.loading = false
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    },
-    validPrefix (str) {
-      if (!str) {
-        return false
-      }
-      return str.match(/[a-z0-9]+/g)
-    },
-    validPrefixLength (str, min, max) {
-      if (!str) {
-        return false
-      }
-      return str.length > min && str.length <= max
-    },
-    validPrefixNotExists (str) {
-      const ontologies = this.ontologies.filter(o => o.prefix === str)
-      if (ontologies && ontologies.length !== 0) {
-        /* same prefix is fine for the same ontology, but not for others */
-        return ontologies[0].id === this.ontology.id
-      }
-      return !this.ontologies.map(o => o.prefix).includes(str)
-    },
-    validUriNotExists (str) {
-      const ontologies = this.ontologies.filter(o => o.uri === str)
-      if (ontologies && ontologies.length !== 0) {
-        /* same uri is fine for the same ontology, but not for others */
-        return ontologies[0].id === this.ontology.id
-      }
-      return !this.ontologies.map(o => o.uri).includes(str)
-    },
-    validUriOptional (str) {
-      if (!str) {
-        return true
-      }
-      return this.validUri(str)
-    },
-    validUri (str) {
-      if (!str) {
-        return false
-      }
-      return str.match(/^https?:\/\//g)
-    },
-    close (event) {
-      if (event.success) {
-        // this.$store.dispatch('reloadOntologies')
-      }
-      this.createOntologyDialog = false
-    },
-    submit () {
-      this.$refs.form.validate()
-    },
-    notEmpty
-  }
-}
-</script>
-<style>
-.skeleton-medium > div {
-  width: 200px !important;
-}
-.skeleton-xsmall > div {
-  width: 50px !important;
-}
-</style>
diff --git a/dbrepo-ui/pages/semantic/ontology/index.vue b/dbrepo-ui/pages/semantic/ontology/index.vue
deleted file mode 100644
index 36898d90739c2d219e9f9987c02527e2409a676f..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/semantic/ontology/index.vue
+++ /dev/null
@@ -1,96 +0,0 @@
-<template>
-  <div v-if="canListOntologies">
-    <v-toolbar flat>
-      <v-btn
-        variant="plain"
-        size="small"
-        icon="mdi-arrow-left"
-        to="/semantic" />
-      <v-toolbar-title>
-        {{ ontologies.length + ' ' + $t('toolbars.semantic.ontologies.title') }}
-      </v-toolbar-title>
-      <v-spacer />
-      <v-btn
-        v-if="canCreateOntology"
-        color="secondary"
-        variant="flat"
-        name="create-ontology"
-        prepend-icon="mdi-plus"
-        :text="$t('toolbars.semantic.ontology.text')"
-        @click.stop="createOntologyDialog = true" />
-    </v-toolbar>
-    <OntologiesList />
-    <v-dialog
-      v-model="createOntologyDialog"
-      persistent
-      max-width="640">
-      <CreateOntology ref="ont" @close="close" />
-    </v-dialog>
-    <v-breadcrumbs :items="items" class="pa-0 mt-2" />
-  </div>
-</template>
-
-<script>
-import OntologiesList from '@/components/OntologiesList.vue'
-import CreateOntology from '@/components/dialogs/CreateOntology.vue'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  components: {
-    OntologiesList,
-    CreateOntology
-  },
-  data () {
-    return {
-      createOntologyDialog: false,
-      items: [
-        {
-          title: `${this.$t('navigation.semantics')}`,
-          to: '/semantic'
-        },
-        {
-          title: `${this.$t('navigation.ontologies')}`,
-          to: '/semantic/ontology'
-        }
-      ],
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    ontologies () {
-      return this.cacheStore.getOntologies
-    },
-    canListOntologies () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('list-ontologies')
-    },
-    canCreateOntology () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('create-ontology')
-    }
-  },
-  methods: {
-    close (event) {
-      if (event.success) {
-        // this.$store.dispatch('reloadOntologies')
-      }
-      this.createOntologyDialog = false
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/signup.vue b/dbrepo-ui/pages/signup.vue
deleted file mode 100644
index 54c00602256c7815d8aff0b255214e66836bc727..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/signup.vue
+++ /dev/null
@@ -1,163 +0,0 @@
-<template>
-  <div>
-    <v-toolbar
-      :title="$t('pages.signup.name')"
-      flat />
-    <v-form
-      ref="form"
-      v-model="valid"
-      @submit.prevent="submit">
-      <v-card
-        variant="flat"
-        rounded="0">
-        <v-card-text>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="createAccount.email"
-                type="email"
-                autocomplete="off"
-                autofocus
-                required
-                name="email"
-                :rules="[v => !!v || $t('validation.required')]"
-                :hint="$t('pages.signup.email.hint')"
-                :label="$t('pages.signup.email.label')" />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="createAccount.username"
-                autocomplete="off"
-                required
-                name="username"
-                :rules="[v => !!v || $t('validation.required'),
-                         v => /^[a-z0-9]{3,}$/.test(v) || $t('validation.user.pattern'),
-                         v => !usernames.includes(v) || $t('validation.user.exists')]"
-                persistent-hint
-                :hint="$t('pages.signup.username.hint')"
-                :label="$t('pages.signup.username.label')" />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="createAccount.password"
-                autocomplete="off"
-                required
-                name="password"
-                :rules="[
-                  v => !!v || $t('validation.required')
-                ]"
-                type="password"
-                persistent-hint
-                :label="$t('pages.signup.password.label')"
-                :hint="$t('pages.signup.password.hint')" />
-            </v-col>
-          </v-row>
-          <v-row dense>
-            <v-col sm="6">
-              <v-text-field
-                v-model="password2"
-                autocomplete="off"
-                required
-                name="password-confirm"
-                :rules="[
-                  v => !!v || $t('validation.required')
-                ]"
-                :error-messages="password2 && password2 !== this.createAccount.password ? [this.$t('validation.matching')] : []"
-                type="password"
-                persistent-hint
-                :label="$t('pages.signup.confirm.label')"
-                :hint="$t('pages.signup.confirm.hint')" />
-            </v-col>
-          </v-row>
-        </v-card-text>
-        <v-card-text>
-          <v-btn
-            id="login"
-            variant="flat"
-            :disabled="!valid"
-            color="primary"
-            type="submit"
-            name="submit"
-            :text="$t('pages.signup.submit.label')"
-            :loading="loading"
-            @click="register" />
-        </v-card-text>
-      </v-card>
-    </v-form>
-  </div>
-</template>
-
-<script>
-export default {
-  data () {
-    return {
-      loading: false,
-      loadingUsers: false,
-      usernames: [],
-      error: false, // XXX: `error` is never changed
-      valid: false,
-      password2: null,
-      privacy: false,
-      consent: false,
-      createAccount: {
-        username: null,
-        email: null,
-        password: null
-      }
-    }
-  },
-  mounted () {
-    this.loadUsers()
-  },
-  methods: {
-    submit () {
-      this.$refs.form.validate()
-    },
-    register () {
-      this.loading = true
-      const userService = useUserService()
-      userService.create(this.createAccount)
-        .then(() => {
-          const toast = useToastInstance()
-          toast.success(this.$t('success.signup'))
-          this.$router.push('/login')
-          this.loading = false
-        })
-        .catch(({code}) => {
-          this.loading = false
-          const toast = useToastInstance()
-          if (typeof code !== 'string') {
-            return
-          }
-          toast.error(this.$t(code))
-        })
-        .finally(() => {
-          this.loading = false
-        })
-    },
-    loadUsers () {
-      this.loadingUsers = true
-      const userService = useUserService()
-      userService.findAll()
-        .then((users) => {
-          this.usernames = users.map(u => u.username)
-        })
-        .catch(({code}) => {
-          this.loadingUsers = false
-          const toast = useToastInstance()
-          if (typeof code !== 'string') {
-            return
-          }
-          toast.error(this.$t(code))
-        })
-        .finally(() => {
-          this.loadingUsers = false
-        })
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/user/authentication.vue b/dbrepo-ui/pages/user/authentication.vue
index 3a43421a709560b3e841760620321f0c640275f9..50008d3c5dab56111fb15ae7a6164e1a591af1f9 100644
--- a/dbrepo-ui/pages/user/authentication.vue
+++ b/dbrepo-ui/pages/user/authentication.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="loggedIn">
     <UserToolbar />
     <v-window v-model="tab">
       <v-window-item>
@@ -10,8 +11,7 @@
           rounded="0">
           <v-card-text>
             <v-form
-              v-model="valid2"
-              @submit.prevent="submit">
+              v-model="valid2">
               <v-row dense>
                 <v-col md="6">
                   <v-text-field
@@ -60,9 +60,12 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import UserToolbar from '@/components/user/UserToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -88,12 +91,12 @@ export default {
       email: null,
       password: null,
       password2: null,
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
@@ -104,15 +107,11 @@ export default {
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal
     }
   },
-  mounted () {
-  },
   methods: {
-    submit () {
-    },
     changePassword () {
       this.loadingUpdate = true
       const userService = useUserService()
-      userService.updatePassword(this.user.id, {'password': this.password})
+      userService.updatePassword(this.cacheUser.uid, {'password': this.password})
         .then(() => {
           const toast = useToastInstance()
           toast.success(this.$t('success.user.password'))
diff --git a/dbrepo-ui/pages/user/developer.vue b/dbrepo-ui/pages/user/developer.vue
deleted file mode 100644
index de52a490aff050b7a7a92c1870645301bf68b9d3..0000000000000000000000000000000000000000
--- a/dbrepo-ui/pages/user/developer.vue
+++ /dev/null
@@ -1,230 +0,0 @@
-<template>
-  <div>
-    <UserToolbar />
-    <v-window
-      v-model="tab">
-      <v-window-item>
-        <v-card
-          v-if="canHandleMessages"
-          :title="$t('pages.settings.subpages.developer.maintenance.title')"
-          rounded="0"
-          variant="flat">
-          <v-data-table
-            :headers="headers"
-            :items="messages"
-            :loading="loadingMessages"
-            :items-per-page="10">
-            <template v-slot:item.action="{ item }">
-              <v-btn
-                size="x-small"
-                variant="flat"
-                :text="$t('pages.settings.subpages.developer.maintenance.modify.text')"
-                @click="modifyMessage(item)" />
-            </template>
-          </v-data-table>
-          <v-card-text>
-            <v-btn
-              size="small"
-              variant="flat"
-              :text="$t('pages.settings.subpages.developer.maintenance.add.text')"
-              :disabled="!canCreateMessage"
-              @click="createMessage" />
-          </v-card-text>
-        </v-card>
-        <v-divider
-          v-if="canHandleMessages" />
-        <v-card
-          :title="$t('pages.settings.subpages.developer.token.title')"
-          :subtitle="$t('pages.settings.subpages.developer.token.subtitle')"
-          variant="flat"
-          rounded="0">
-          <v-card-text>
-            <v-row dense>
-              <v-col xl="4">
-                <v-text-field
-                  v-model="accessTokenField"
-                  disabled
-                  :variant="inputVariant"
-                  :label="$t('pages.settings.subpages.developer.token.access.label')" />
-              </v-col>
-              <v-col xl="2">
-                <v-text-field
-                  v-model="tokenExpiry"
-                  disabled
-                  :variant="inputVariant"
-                  :label="expiryLabel(token)" />
-              </v-col>
-            </v-row>
-            <v-row dense>
-              <v-col xl="4">
-                <v-text-field
-                  v-model="refreshTokenField"
-                  disabled
-                  :variant="inputVariant"
-                  :label="$t('pages.settings.subpages.developer.token.refresh.label')" />
-              </v-col>
-              <v-col xl="2">
-                <v-text-field
-                  v-model="refreshTokenExpiry"
-                  disabled
-                  :variant="inputVariant"
-                  :label="expiryLabel(refreshToken)" />
-              </v-col>
-            </v-row>
-          </v-card-text>
-        </v-card>
-      </v-window-item>
-    </v-window>
-    <v-breadcrumbs :items="items" class="pa-0 mt-2" />
-    <v-dialog
-      v-model="dialog"
-      persistent
-      max-width="640">
-      <EditMaintenanceMessage
-        :id="messageId"
-        @close-dialog="closeDialog" />
-    </v-dialog>
-  </div>
-</template>
-
-<script>
-import UserToolbar from '@/components/user/UserToolbar.vue'
-import EditMaintenanceMessage from '@/components/dialogs/EditMaintenanceMessage.vue'
-import { formatTimestampUTCLabel, isActiveMessage, timestampsToHumanDifference } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
-import { useCacheStore } from '@/stores/cache.js'
-
-export default {
-  components: {
-    UserToolbar,
-    EditMaintenanceMessage
-  },
-  data () {
-    return {
-      tab: 0,
-      accessTokenField: null,
-      refreshTokenField: null,
-      headers: [
-        { title: this.$t('pages.settings.subpages.developer.maintenance.active'), value: 'active' },
-        { title: this.$t('pages.settings.subpages.developer.maintenance.type'), value: 'type' },
-        { title: this.$t('pages.settings.subpages.developer.maintenance.message'), value: 'message' },
-        { title: this.$t('pages.settings.subpages.developer.maintenance.action'), value: 'action' }
-      ],
-      items: [
-        {
-          title: this.$t('navigation.user'),
-          to: '/user'
-        },
-        {
-          title: this.$t('toolbars.user.developer'),
-          to: `/user/developer`,
-          disabled: true
-        }
-      ],
-      messages: [],
-      loadingMessages: false,
-      dialog: false,
-      messageId: null,
-      userStore: useUserStore(),
-      cacheStore: useCacheStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    tokenExpiry () {
-      if (!this.token) {
-        return null
-      }
-      const authenticationService = useAuthenticationService()
-      return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.token))
-    },
-    refreshToken () {
-      return this.userStore.getRefreshToken
-    },
-    refreshTokenExpiry () {
-      if (!this.refreshToken) {
-        return null
-      }
-      const authenticationService = useAuthenticationService()
-      return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.refreshToken))
-    },
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    canCreateMessage () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('create-maintenance-message')
-    },
-    canModifyMessage () {
-      if (!this.roles) {
-        return false
-      }
-      return this.roles.includes('modify-maintenance-message')
-    },
-    canHandleMessages () {
-      return this.canCreateMessage || this.canModifyMessage
-    },
-    inputVariant () {
-      const runtimeConfig = useRuntimeConfig()
-      return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : runtimeConfig.public.variant.input.normal
-    },
-    buttonVariant () {
-      const runtimeConfig = useRuntimeConfig()
-      return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal
-    }
-  },
-  mounted () {
-    this.loadMessages()
-    if (!this.token || !this.refreshToken) {
-      return
-    }
-    this.accessTokenField = this.token
-    this.refreshTokenField = this.refreshToken
-  },
-  methods: {
-    submit () {
-    },
-    modifyMessage (message) {
-      this.messageId = message.id
-      this.dialog = true
-    },
-    createMessage () {
-      this.messageId = null
-      this.dialog = true
-    },
-    expiryLabel (token) {
-      const authenticationService = useAuthenticationService()
-      return this.$t('pages.settings.subpages.developer.token.expiry') + ' ' + timestampsToHumanDifference(Date.now(), authenticationService.tokenToExpiryDate(token))
-    },
-    loadMessages () {
-      const messageService = useMessageService()
-      messageService.findAll()
-        .then((messages) => {
-          this.messages = messages.map((message) => {
-            message.active = isActiveMessage(message) ? '● true' : 'false'
-            return message
-          })
-        })
-        .catch(() => {
-          this.loadingMessages = false
-        })
-        .finally(() => {
-          this.loadingMessages = false
-        })
-    },
-    closeDialog (event) {
-      if (event.success) {
-        this.cacheStore.reloadMessages()
-      }
-      this.dialog = false
-    }
-  }
-}
-</script>
diff --git a/dbrepo-ui/pages/user/index.vue b/dbrepo-ui/pages/user/index.vue
index accae861052044324dc08ae48f6858e643172c5f..aa8ee559441bfdc4dd29380d77a98662c476ed79 100644
--- a/dbrepo-ui/pages/user/index.vue
+++ b/dbrepo-ui/pages/user/index.vue
@@ -3,24 +3,10 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
-
 export default {
-  data () {
-    return {
-      userStore: useUserStore()
-    }
-  },
-  computed: {
-    token () {
-      return this.userStore.getToken
-    },
-    user () {
-      return this.userStore.getUser
-    }
-  },
   mounted () {
-    if (!this.user) {
+    const { loggedIn } = useOidcAuth()
+    if (!loggedIn) {
       return
     }
     this.$router.push('/user/info')
diff --git a/dbrepo-ui/pages/user/info.vue b/dbrepo-ui/pages/user/info.vue
index 9b94dde4dad312bb648e992efbc38120798bf869..470b7bc438a0211d80ad44f06411f1da7f54dddc 100644
--- a/dbrepo-ui/pages/user/info.vue
+++ b/dbrepo-ui/pages/user/info.vue
@@ -1,9 +1,12 @@
 <template>
-  <div>
+  <div
+    v-if="loggedIn">
     <UserToolbar />
-    <v-window v-model="tab">
+    <v-window
+      v-model="tab">
       <v-window-item>
-        <v-form v-model="valid1" @submit.prevent="submit">
+        <v-form
+          v-model="valid1">
           <v-card
             :title="$t('pages.user.subpages.info.title')"
             :subtitle="$t('pages.user.subpages.info.subtitle')"
@@ -19,10 +22,12 @@
                     :label="$t('pages.user.subpages.info.id.label')" />
                 </v-col>
               </v-row>
-              <v-row dense>
+              <v-row
+                v-if="cacheUser"
+                dense>
                 <v-col md="6">
                   <v-text-field
-                    v-model="model.username"
+                    v-model="cacheUser.preferred_username"
                     disabled
                     :variant="inputVariant"
                     :label="$t('pages.user.subpages.info.username.label')"  />
@@ -122,9 +127,12 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn } = useOidcAuth()
+</script>
 <script>
 import UserToolbar from '@/components/user/UserToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -138,15 +146,16 @@ export default {
       error: false,
       loadingUpdate: false,
       loadingTheme: false,
-      theme: null,
       orcidLoading: false,
       model: {
         id: null,
-        username: null,
+        preferred_username: null,
         firstname: null,
         lastname: null,
         theme: null,
-        language: null
+        language: null,
+        orcid: null,
+        affiliation: null
       },
       themes: [
         { name: this.$t('pages.user.subpages.theme.light'), value: 'light' },
@@ -169,23 +178,23 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
+    locale () {
+      return this.cacheStore.getLocale
     },
     roles () {
-      return this.userStore.getRoles
+      return this.cacheStore.getRoles
     },
-    locale () {
-      return this.userStore.getLocale
-    },
-    canModifyTheme () {
-      return this.roles.includes('modify-user-theme')
+    cacheUser () {
+      return this.cacheStore.getUser
     },
     canModifyInformation () {
+      if (!this.roles) {
+        return false
+      }
       return this.roles.includes('modify-user-information')
     },
     inputVariant () {
@@ -201,8 +210,6 @@ export default {
     this.init()
   },
   methods: {
-    submit () {
-    },
     updateInfo () {
       this.loadingUpdate = true
       const payload = {
@@ -211,17 +218,16 @@ export default {
         orcid: this.model.orcid,
         affiliation: this.model.affiliation,
         theme: this.model.theme,
-        language: this.model.language,
+        language: this.model.language
       }
       const userService = useUserService()
-      userService.update(this.user.id, payload)
+      userService.update(this.cacheUser.uid, payload)
         .then((user) => {
           console.info('Updated user information')
           const toast = useToastInstance()
           toast.success(this.$t('success.user.info'))
-          this.userStore.setUser(user)
           /* language */
-          this.userStore.setLocale(this.model.language)
+          this.cacheStore.setLocale(this.model.language)
           this.$i18n.locale = this.locale
           /* theme */
           switch (this.model.theme) {
@@ -247,18 +253,18 @@ export default {
         })
     },
     init () {
-      if (!this.user) {
+      if (!this.cacheUser) {
         return
       }
       this.model = {
-        id: this.user.id,
-        username: this.user.username,
-        firstname: this.user.given_name,
-        lastname: this.user.family_name,
-        orcid: this.user.attributes.orcid,
-        affiliation: this.user.attributes.affiliation,
-        theme: this.user.attributes.theme,
-        language: this.user.attributes.language
+        id: this.cacheUser.uid,
+        username: this.cacheUser.username,
+        firstname: this.cacheUser.given_name,
+        lastname: this.cacheUser.family_name,
+        orcid: this.cacheUser.orcid,
+        affiliation: this.cacheUser.affiliation,
+        theme: this.cacheUser.theme ? this.cacheUser.theme : 'light',
+        language: this.cacheUser.language ? this.cacheUser.language : 'en'
       }
     },
     retrieve () {
diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js
index 41059ba7270d93717998ac5b245e37d6ed239ee3..c2e34f48bbc9bedc8d4afc31c9158963a9450749 100644
--- a/dbrepo-ui/stores/cache.js
+++ b/dbrepo-ui/stores/cache.js
@@ -7,9 +7,14 @@ export const useCacheStore = defineStore('cache', {
       database: null,
       table: null,
       view: null,
+      access: null,
       subset: null,
+      locale: null,
+      identifier: null,
       ontologies: [],
       messages: [],
+      user: null,
+      roles: [],
       uploadProgress: null
     }
   },
@@ -17,9 +22,14 @@ export const useCacheStore = defineStore('cache', {
     getDatabase: (state) => state.database,
     getTable: (state) => state.table,
     getView: (state) => state.view,
+    getAccess: (state) => state.access,
     getSubset: (state) => state.subset,
+    getLocale: (state) => state.locale,
+    getIdentifier: (state) => state.identifier,
     getOntologies: (state) => state.ontologies,
     getMessages: (state) => state.messages,
+    getUser: (state) => state.user,
+    getRoles: (state) => state.roles,
     getUploadProgress: (state) => state.uploadProgress,
   },
   actions: {
@@ -32,12 +42,27 @@ export const useCacheStore = defineStore('cache', {
     setView(view) {
       this.view = view
     },
+    setAccess(access) {
+      this.access = access
+    },
     setSubset(subset) {
       this.subset = subset
     },
+    setLocale(locale) {
+      this.locale = locale
+    },
+    setIdentifier(identifier) {
+      this.identifier = identifier
+    },
     setOntologies(ontologies) {
       this.ontologies = ontologies
     },
+    setUser(user) {
+      this.user = user
+    },
+    setRoles(roles) {
+      this.roles = roles
+    },
     setUploadProgress(uploadProgress) {
       this.uploadProgress = uploadProgress
     },
@@ -110,17 +135,24 @@ export const useCacheStore = defineStore('cache', {
     setRouteTable(databaseId, tableId) {
       if (!databaseId || !tableId) {
         this.table = null
-        console.error('Cannot set route table: missing database id', databaseId, 'or table id', tableId)
         return
       }
       const tableService = useTableService()
       tableService.findOne(databaseId, tableId)
         .then(table => this.table = table)
     },
+    setRouteAccess(databaseId, userId) {
+      if (!databaseId || !userId) {
+        this.access = null
+        return
+      }
+      const accessService = useAccessService()
+      accessService.findOne(databaseId, userId)
+        .then(access => this.access = access)
+    },
     setRouteView(databaseId, viewId) {
       if (!databaseId || !viewId) {
         this.view = null
-        console.error('Cannot set route view: database view id', databaseId, 'or view id', viewId)
         return
       }
       const viewService = useViewService()
@@ -130,7 +162,6 @@ export const useCacheStore = defineStore('cache', {
     setRouteSubset(databaseId, subsetId) {
       if (!databaseId || !subsetId) {
         this.subset = null
-        console.error('Cannot set route subset: missing database id', databaseId, 'or subset id', subsetId)
         return
       }
       const subsetService = useQueryService()
diff --git a/dbrepo-ui/stores/user.js b/dbrepo-ui/stores/user.js
deleted file mode 100644
index 522ce02a06ed1c695897d92a73c2682d791b499a..0000000000000000000000000000000000000000
--- a/dbrepo-ui/stores/user.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import {defineStore} from 'pinia'
-
-export const useUserStore = defineStore('user', {
-  persist: true,
-  state: () => {
-    return {
-      /** @type String */
-      token: null,
-      /** @type String */
-      refreshToken: null,
-      roles: [],
-      user: null,
-      access: null,
-      locale: null
-    }
-  },
-  getters: {
-    getToken: (state) => state.token,
-    getRefreshToken: (state) => state.refreshToken,
-    getRoles: (state) => state.roles,
-    getUser: (state) => state.user,
-    getAccess: (state) => state.access,
-    getLocale: (state) => state.locale
-  },
-  actions: {
-    setToken(token) {
-      this.token = token
-    },
-    setRefreshToken(refreshToken) {
-      this.refreshToken = refreshToken
-    },
-    setRoles(roles) {
-      this.roles = roles
-    },
-    setUser(user) {
-      this.user = user
-    },
-    setAccess(access) {
-      this.access = access
-    },
-    setLocale (locale) {
-      this.locale = locale
-    },
-    logout() {
-      this.token = null
-      this.refreshToken = null
-      this.roles = []
-      this.user = null
-      this.access = null
-    },
-    setRouteAccess(databaseId) {
-      if (!databaseId || !this.user || !this.user.id) {
-        return
-      }
-      const accessService = useAccessService()
-      accessService.findOne(databaseId, this.user.id)
-        .then(access => this.access = access)
-    }
-  }
-})
diff --git a/dbrepo-upload-service/pom.xml b/dbrepo-upload-service/pom.xml
index 8f4506e150cfef06abcbb4e54e71d4b3e3ddccd1..20f379e32e7e58ab53dedc75c230071a2759c3cd 100644
--- a/dbrepo-upload-service/pom.xml
+++ b/dbrepo-upload-service/pom.xml
@@ -11,7 +11,7 @@
     <groupId>at.tuwien</groupId>
     <artifactId>dbrepo-upload-service</artifactId>
     <name>dbrepo-upload-service</name>
-    <version>1.6.2</version>
+    <version>1.6.3</version>
 
     <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url>
     <developers>
diff --git a/dbrepo-upload-service/pre-create.sh b/dbrepo-upload-service/pre-create.sh
index 536a2e63e060c32db1882bbaad7f4de02cc3d2f7..2d6eb4f861297db095e9dcf5268ed858fde7cd6d 100755
--- a/dbrepo-upload-service/pre-create.sh
+++ b/dbrepo-upload-service/pre-create.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 REQUEST_RAW=$(cat /dev/stdin)
-AUTH_SERVICE_ENDPOINT="${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}"
+METADATA_SERVICE_ENDPOINT="${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}"
 
 echo "[DEBUG] [pre-create hook] request started" >&2
 if [ "$(echo "$REQUEST_RAW" | jq '.Event.HTTPRequest.Header | has("Authorization")')" == "false" ]; then
@@ -21,11 +21,11 @@ END
   exit 0
 fi
 
-echo "[DEBUG] [pre-create hook] request has 'Authorization' header present" >&2
+echo "[DEBUG] [pre-create hook] request has 'Authorization' header p  resent" >&2
 
 BEARER="$(echo "$REQUEST_RAW" | jq -r '.Event.HTTPRequest.Header.Authorization[0]')"
-echo "[DEBUG] [pre-create hook] attempting to contact ${AUTH_SERVICE_ENDPOINT}" >&2
-if [ ! "$(wget -O- --quiet --header "Authorization: ${BEARER}" ${AUTH_SERVICE_ENDPOINT}/realms/dbrepo/protocol/openid-connect/userinfo)" ]; then
+
+if [ ! "$(wget -O- --quiet --header='Authorization: ${BEARER}' ${METADATA_SERVICE_ENDPOINT}/api/license)" ]; then
   echo "[ERROR] [pre-create hook] Unauthorized" >&2
   cat <<END
   {
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java b/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java
index e360cecfdc106386a1229cfd12de189a8b57d60c..601229b5e5ae64da214820b2f91396a926d77884 100644
--- a/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java
@@ -1,13 +1,11 @@
 package at.tuwien.config;
 
-import at.tuwien.interceptor.KeycloakInterceptor;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 @Log4j2
 @Getter
@@ -28,13 +26,4 @@ public class GatewayConfig {
         return new RestTemplate();
     }
 
-    @Bean("keycloakRestTemplate")
-    public RestTemplate keycloakRestTemplate() {
-        final RestTemplate restTemplate = new RestTemplate();
-        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint));
-        restTemplate.getInterceptors()
-                .add(new KeycloakInterceptor(restTemplate(), keycloakUsername, keycloakPassword, keycloakEndpoint));
-        return restTemplate;
-    }
-
 }
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java
index 01be743daa98d258391d3d9c4e6bdec7aa4f8773..6243cb3ab5ecffc614cf71391886cae1852d30a2 100644
--- a/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java
@@ -1,25 +1,11 @@
 package at.tuwien.config;
 
-import at.tuwien.api.auth.KeycloakErrorDto;
-import at.tuwien.api.keycloak.UserCreateDto;
-import at.tuwien.api.keycloak.UserDto;
-import at.tuwien.exception.AuthServiceConnectionException;
-import at.tuwien.exception.AuthServiceException;
-import at.tuwien.exception.EmailExistsException;
-import at.tuwien.exception.UserExistsException;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
+import org.keycloak.admin.client.Keycloak;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.client.RestTemplate;
 
 @Log4j2
 @Getter
@@ -29,55 +15,9 @@ public class KeycloakConfig {
     @Value("${dbrepo.endpoints.keycloak}")
     private String keycloakEndpoint;
 
-    @Autowired
-    @Qualifier("keycloakRestTemplate")
-    private RestTemplate keycloakRestTemplate;
-
-    public Boolean existsByUsername(String username) throws AuthServiceException, AuthServiceConnectionException {
-        final String path = "/admin/realms/dbrepo/users/?username=" + username;
-        final ResponseEntity<UserDto[]> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto[].class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to find user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (Exception e) {
-            log.error("Failed to find user: unexpected response: {}", e.getMessage());
-            throw new AuthServiceException("Unexpected result", e);
-        }
-        final UserDto[] body = response.getBody();
-        if (body == null || body.length != 1) {
-            log.error("Failed to find user with username {}", username);
-            return false;
-        }
-        return true;
-    }
-
-    public void createUser(UserCreateDto data) throws UserExistsException, EmailExistsException,
-            AuthServiceConnectionException, AuthServiceException {
-        final String path = "/admin/realms/dbrepo/users";
-        final ResponseEntity<Void> response;
-        try {
-            response = keycloakRestTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), Void.class);
-        } catch (HttpServerErrorException e) {
-            log.error("Failed to create user: {}", e.getMessage());
-            throw new AuthServiceConnectionException("Service unavailable", e);
-        } catch (HttpClientErrorException.Conflict e) {
-            if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) {
-                final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class);
-                if (error != null && error.getErrorMessage().contains("same email")) {
-                    log.error("Failed to create user: email exists: {}", e.getMessage());
-                    throw new EmailExistsException("E-Mail exists", e);
-                }
-            }
-            log.error("Failed to create user: user exists: {}", e.getMessage());
-            throw new UserExistsException("User exists", e);
-        }
-        if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
-            log.error("Failed to create user: unexpected status: {}", response.getStatusCode().value());
-            throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value());
-        }
-        log.debug("Created user {} at auth service", data.getUsername());
+    @Bean
+    public Keycloak keycloak() {
+        return Keycloak.getInstance(keycloakEndpoint, "master", "admin", "admin", "admin-cli");
     }
 
 }
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6b5d429e7b87b1a3a4759167f794ad183311883
--- /dev/null
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java
@@ -0,0 +1,22 @@
+package at.tuwien.mapper;
+
+
+import at.tuwien.api.keycloak.UserCreateDto;
+import at.tuwien.api.user.external.ExternalResultType;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+
+import java.util.LinkedList;
+
+@Mapper(componentModel = "spring", imports = {LinkedList.class, ExternalResultType.class})
+public interface MetadataMapper {
+
+    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class);
+
+    @Mappings({
+            @Mapping(target = "attributes", ignore = true)
+    })
+    UserRepresentation userCreateDtoToUserRepresentation(UserCreateDto data);
+}
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java b/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java
index 30fd6752c3b37a20487aa4133aefdefcbdf3e4b0..052d028d39478f3f8a61b2639bf8bfe8487af9ba 100644
--- a/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java
@@ -7,11 +7,9 @@ import at.tuwien.api.keycloak.UserCreateDto;
 import at.tuwien.config.KeycloakConfig;
 import at.tuwien.config.TusdConfig;
 import at.tuwien.config.TusdContainerConfig;
-import at.tuwien.exception.AuthServiceConnectionException;
 import at.tuwien.exception.AuthServiceException;
-import at.tuwien.exception.EmailExistsException;
-import at.tuwien.exception.UserExistsException;
 import at.tuwien.interceptor.KeycloakInterceptor;
+import at.tuwien.util.KeycloakUtil;
 import com.github.dockerjava.api.model.ExposedPort;
 import dasniko.testcontainers.keycloak.KeycloakContainer;
 import lombok.extern.log4j.Log4j2;
@@ -20,7 +18,10 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.*;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.DynamicPropertyRegistry;
 import org.springframework.test.context.DynamicPropertySource;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -33,7 +34,6 @@ import org.testcontainers.junit.jupiter.Testcontainers;
 
 import java.util.List;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 @Log4j2
@@ -48,6 +48,9 @@ public class UploadServiceIntegrationTest {
     @Autowired
     private TusdConfig tusdConfig;
 
+    @Autowired
+    private KeycloakUtil keycloakUtil;
+
     @Autowired
     private KeycloakConfig keycloakConfig;
 
@@ -55,7 +58,7 @@ public class UploadServiceIntegrationTest {
     private static TusdContainerConfig.TusdContainer tusdContainer = TusdContainerConfig.TusdContainer.getInstance();
 
     @Container
-    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0")
+    private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:26.0")
             .withImagePullPolicy(PullPolicy.alwaysPull())
             .withRealmImportFile("init/dbrepo-realm.json")
             .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false")
@@ -69,9 +72,8 @@ public class UploadServiceIntegrationTest {
     }
 
     @BeforeEach
-    public void beforeEach() throws UserExistsException, AuthServiceException, AuthServiceConnectionException,
-            EmailExistsException {
-        if (keycloakConfig.existsByUsername(keycloakContainer.getAdminUsername())) {
+    public void beforeEach() throws AuthServiceException {
+        if (keycloakUtil.existsByUsername(keycloakContainer.getAdminUsername())) {
             return;
         }
         final UserCreateDto payload = UserCreateDto.builder()
@@ -82,7 +84,7 @@ public class UploadServiceIntegrationTest {
                         .value(keycloakContainer.getAdminPassword())
                         .build()))
                 .build();
-        keycloakConfig.createUser(payload);
+        keycloakUtil.createUser(payload);
     }
 
     @Test
diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java b/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7c24cab9d5221f893e2e1fceb3f378b59e6d684
--- /dev/null
+++ b/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java
@@ -0,0 +1,46 @@
+package at.tuwien.util;
+
+import at.tuwien.api.keycloak.UserCreateDto;
+import at.tuwien.exception.AuthServiceException;
+import at.tuwien.mapper.MetadataMapper;
+import jakarta.ws.rs.core.Response;
+import lombok.extern.log4j.Log4j2;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+@Log4j2
+public class KeycloakUtil {
+
+
+    private final MetadataMapper metadataMapper;
+    private final Keycloak keycloak;
+
+    @Autowired
+    public KeycloakUtil(MetadataMapper metadataMapper, Keycloak keycloak) {
+        this.metadataMapper = metadataMapper;
+        this.keycloak = keycloak;
+    }
+
+    public void createUser(UserCreateDto data) throws AuthServiceException {
+        final UserRepresentation user = metadataMapper.userCreateDtoToUserRepresentation(data);
+        try (Response response = keycloak.realm("dbrepo")
+                .users()
+                .create(user)) {
+            if (response.getStatus() != 200) {
+                log.error("Failed to delete user: unexpected response status: {}", response.getStatus());
+                throw new AuthServiceException("Unexpected response status: " + response.getStatus());
+            }
+        }
+        log.info("Created user at auth service");
+    }
+
+    public boolean existsByUsername(String username) {
+        return keycloak.realm("dbrepo")
+                .users()
+                .search(username)
+                .isEmpty();
+    }
+}
diff --git a/docker-compose.yml b/docker-compose.yml
index ad1dacb6b7b19a8fb4ee3303968cd684bef75967..9176f6404a06df5e30269f4a0dde4d8e4483ebd8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -80,20 +80,25 @@ services:
     restart: "no"
     container_name: dbrepo-auth-service
     hostname: auth-service
-    image: bitnami/keycloak:24.0.5-debian-12-r8
+    image: bitnami/keycloak:26.0.4-debian-12-r0
     volumes:
       - ./dbrepo-auth-service/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh
       - ./dbrepo-auth-service/master-realm.json:/opt/keycloak/data/import/master-realm.json
       - ./dbrepo-auth-service/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json
+      - ./dbrepo-auth-service/listeners/target/create-event-listener.jar:/opt/bitnami/keycloak/providers/create-event-listener.jar
     ports:
       - "8080:8080"
     environment:
+      KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true"
       KEYCLOAK_ENABLE_HTTPS: "false"
       KEYCLOAK_ENABLE_STATISTICS: "true"
       KEYCLOAK_DATABASE_HOST: "auth-db"
       KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}"
       KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}"
       KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}/api/user"
+      SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}"
+      SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}"
     healthcheck:
       test: curl -fsS http://localhost:8080/realms/master
       interval: 10s
@@ -331,6 +336,14 @@ services:
       NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}"
       NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}"
       NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/auth"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "${AUTH_SERVICE_CLIENT:-dbrepo-client}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "${BASE_URL:-http://localhost}"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/logout"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "${BASE_URL:-http://localhost}/auth/keycloak/callback"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/token"
+      NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/userinfo"
     depends_on:
       dbrepo-search-service:
         condition: service_healthy
@@ -341,6 +354,8 @@ services:
       interval: 10s
       timeout: 5s
       retries: 12
+    extra_hosts:
+      - "localhost:host-gateway"
     logging:
       driver: json-file
 
@@ -475,7 +490,7 @@ services:
       LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}"
       LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}"
     healthcheck:
-      test: test -f /opt/bitnami/grafana/tmp/grafana.pid
+      test: curl -fsSL --head http://127.0.0.1:3000
       interval: 10s
       timeout: 5s
       retries: 12
@@ -523,6 +538,7 @@ services:
       AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}"
       AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}"
       AWS_REGION: "${STORAGE_REGION_NAME:-default}"
+      METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}"
     depends_on:
       dbrepo-storage-service:
         condition: service_healthy
diff --git a/helm/dbrepo/Chart.lock b/helm/dbrepo/Chart.lock
index 4d2cafe9bd7d4dca5c51c603d87e0ce69a9fd0de..297b4b1a9287732c869533cd2f2fe261ae43f4a5 100644
--- a/helm/dbrepo/Chart.lock
+++ b/helm/dbrepo/Chart.lock
@@ -4,7 +4,7 @@ dependencies:
   version: 1.4.0
 - name: keycloak
   repository: https://charts.bitnami.com/bitnami
-  version: 21.6.2
+  version: 24.0.3
 - name: mariadb-galera
   repository: https://charts.bitnami.com/bitnami
   version: 13.2.7
@@ -26,5 +26,5 @@ dependencies:
 - name: nginx
   repository: https://charts.bitnami.com/bitnami
   version: 18.3.1
-digest: sha256:414c043a3751945d7bd5b02fa00ee0464bee7f08efb469e00a5f059cdbff03b5
-generated: "2025-01-19T17:22:48.686050629+01:00"
+digest: sha256:aa148a5f656ad17971203ea710206117d6de6f27b6940f9d532a6c5762e5df25
+generated: "2025-02-04T22:01:27.370259572+01:00"
diff --git a/helm/dbrepo/Chart.yaml b/helm/dbrepo/Chart.yaml
index 802f33888ca44b48351b7f501be5dd893dc6d6ab..99f8a84d23b7808e81dd94a337655594abf1721f 100644
--- a/helm/dbrepo/Chart.yaml
+++ b/helm/dbrepo/Chart.yaml
@@ -7,8 +7,8 @@ description: Helm Chart for installing DBRepo
 sources:
   - https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services
 type: application
-version: "1.6.2"
-appVersion: "1.6.2"
+version: "1.6.3"
+appVersion: "1.6.3"
 keywords:
   - dbrepo
 maintainers:
@@ -24,7 +24,7 @@ dependencies:
     condition: searchdb.enabled
   - name: keycloak
     alias: authservice
-    version: 21.6.1  # app version: 24.0.5
+    version: 24.0.3  # app version: 26.0.4
     repository: https://charts.bitnami.com/bitnami
     condition: authservice.enabled
   - name: mariadb-galera
diff --git a/helm/dbrepo/README.md b/helm/dbrepo/README.md
index e703787206de08f933748b51f951bf80c01712a8..a45297396372cc5580e4f065e4f7172929ba7c5a 100644
--- a/helm/dbrepo/README.md
+++ b/helm/dbrepo/README.md
@@ -11,7 +11,7 @@ sample [
 for your deployment and update the variables, especially `hostname`.
 
 ```bash
-helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.6.2"
+helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.6.3"
 ```
 
 ## Prerequisites
@@ -28,7 +28,7 @@ helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo"
 To install the chart with the release name `my-release`:
 
 ```bash
-helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.6.2"
+helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.6.3"
 ```
 
 The command deploys DBRepo on the Kubernetes cluster in the default configuration. The Parameters section lists the
@@ -86,6 +86,7 @@ The command removes all the Kubernetes components associated with the chart and
 | `authservice.enabled`                  | Enable the Auth Service.                                                                                          | `true`                                                                                                                                                                                                                                                                                                                                                                                                     |
 | `authservice.image.debug`              | Set the logging level to `trace`. Otherwise, set to `info`.                                                       | `false`                                                                                                                                                                                                                                                                                                                                                                                                    |
 | `authservice.endpoint`                 | The hostname for the microservices.                                                                               | `http://auth-service`                                                                                                                                                                                                                                                                                                                                                                                      |
+| `authservice.production`               | Start Keycloak with production profile.                                                                           | `true`                                                                                                                                                                                                                                                                                                                                                                                                     |
 | `authservice.resourcesPreset`          | The container resource presets                                                                                    | `small`                                                                                                                                                                                                                                                                                                                                                                                                    |
 | `authservice.jwt.pubkey`               | The JWT public key from the `dbrepo-client`.                                                                      | `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB` |
 | `authservice.tls.enabled`              | Enable TLS/SSL communication. Required for HTTPS.                                                                 | `true`                                                                                                                                                                                                                                                                                                                                                                                                     |
@@ -388,7 +389,7 @@ mqtt.prefetch = 10
 | `ui.public.pid.default.publisher`                      | The default dataset publisher for persisted identifiers.                                                          | `Example University`    |
 | `ui.public.doi.enabled`                                | Enable the display that DOIs are minted.                                                                          | `false`                 |
 | `ui.public.doi.endpoint`                               | The DOI proxy.                                                                                                    | `https://doi.org`       |
-| `ui.replicaCount`                                      | The number of replicas.                                                                                           | `2`                     |
+| `ui.replicaCount`                                      | The number of replicas.                                                                                           | `1`                     |
 
 ### Dashboard Service
 
diff --git a/helm/dbrepo/charts/keycloak-21.6.1.tgz b/helm/dbrepo/charts/keycloak-21.6.1.tgz
deleted file mode 100644
index 6479f5943846dee589d3ec90bbda649a8d7b72fe..0000000000000000000000000000000000000000
Binary files a/helm/dbrepo/charts/keycloak-21.6.1.tgz and /dev/null differ
diff --git a/helm/dbrepo/charts/keycloak-24.0.3.tgz b/helm/dbrepo/charts/keycloak-24.0.3.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..29a964b44168bec6c04969e16cf51c94b75952fc
Binary files /dev/null and b/helm/dbrepo/charts/keycloak-24.0.3.tgz differ
diff --git a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz
index 6fd5807b55c4d6ad8041d96ca5d4a39ed3795138..a463170406b9c62f8f33ba315ac440fe435ad93c 100644
Binary files a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz and b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz differ
diff --git a/helm/dbrepo/files/01-setup-schema.sql b/helm/dbrepo/files/01-setup-schema.sql
index c9ce89d1be71f4791c5e55dbb7c24f46e979355a..e2bde25ed6d64f69c4f8d6e897a49a672e3f9a71 100644
--- a/helm/dbrepo/files/01-setup-schema.sql
+++ b/helm/dbrepo/files/01-setup-schema.sql
@@ -3,10 +3,10 @@ BEGIN;
 CREATE TABLE IF NOT EXISTS `mdb_users`
 (
     id               character varying(36)  NOT NULL,
+    keycloak_id      character varying(36)  NOT NULL,
     username         character varying(255) NOT NULL,
     firstname        character varying(255),
     lastname         character varying(255),
-    email            character varying(255) NOT NULL,
     orcid            character varying(255),
     affiliation      character varying(255),
     is_internal      BOOLEAN                NOT NULL DEFAULT FALSE,
@@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS `mdb_users`
     theme            character varying(255) NOT NULL default ('light'),
     language         character varying(3)   NOT NULL default ('en'),
     PRIMARY KEY (id),
-    UNIQUE (username),
-    UNIQUE (email)
+    UNIQUE (keycloak_id),
+    UNIQUE (username)
 ) WITH SYSTEM VERSIONING;
 
 CREATE TABLE IF NOT EXISTS `mdb_images`
diff --git a/helm/dbrepo/files/create-event-listener.jar b/helm/dbrepo/files/create-event-listener.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9a9cd149f84ff92e5292a9fdc19a81edcc9ca7b7
Binary files /dev/null and b/helm/dbrepo/files/create-event-listener.jar differ
diff --git a/helm/dbrepo/templates/auth-configmap.yaml b/helm/dbrepo/templates/auth-configmap.yaml
index ffd14c4b1765cab2f20af5888c746fbf47a71a45..28ad32d66494ba0a284b73354af7e240bff48dd4 100644
--- a/helm/dbrepo/templates/auth-configmap.yaml
+++ b/helm/dbrepo/templates/auth-configmap.yaml
@@ -4,8 +4,11 @@ kind: ConfigMap
 metadata:
   name: auth-service-config
   namespace: {{ include "common.names.namespace" . | quote }}
+binaryData:
+  create-event-listener.jar: |-
+    {{ .Files.Get "files/create-event-listener.jar" | b64enc }}
 data:
-  dbrepo-realm.json: |
+  dbrepo-realm.json: |-
     {
       "id" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
       "realm" : "dbrepo",
@@ -35,7 +38,7 @@ data:
       "oauth2DevicePollingInterval" : 5,
       "enabled" : true,
       "sslRequired" : "none",
-      "registrationAllowed" : false,
+      "registrationAllowed" : true,
       "registrationEmailAsUsername" : false,
       "rememberMe" : false,
       "verifyEmail" : true,
@@ -46,6 +49,7 @@ data:
       "bruteForceProtected" : false,
       "permanentLockout" : false,
       "maxTemporaryLockouts" : 0,
+      "bruteForceStrategy" : "MULTIPLE",
       "maxFailureWaitSeconds" : 900,
       "minimumQuickLoginWaitSeconds" : 60,
       "waitIncrementSeconds" : 60,
@@ -1316,8 +1320,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
-          "client.use.lightweight.access.token.enabled" : "true"
+          "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+"
         },
         "authenticationFlowBindingOverrides" : { },
         "fullScopeAllowed" : true,
@@ -1391,6 +1395,38 @@ data:
         "fullScopeAllowed" : true,
         "nodeReRegistrationTimeout" : -1,
         "protocolMappers" : [ {
+          "id" : "266edf62-a19a-483b-b594-81428e4af792",
+          "name" : "orcid",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "ORCID",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "orcid",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "1a21798a-38b6-4df5-89f0-86942415246f",
+          "name" : "theme",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "THEME",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "theme",
+            "jsonType.label" : "String"
+          }
+        }, {
           "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d",
           "name" : "preferred_username",
           "protocol" : "openid-connect",
@@ -1404,18 +1440,66 @@ data:
             "userinfo.token.claim" : "true"
           }
         }, {
-          "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc",
-          "name" : "aud",
+          "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a",
+          "name" : "affiliation",
           "protocol" : "openid-connect",
-          "protocolMapper" : "oidc-hardcoded-claim-mapper",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "claim.value" : "dbrepo",
+            "introspection.token.claim" : "true",
             "userinfo.token.claim" : "true",
+            "user.attribute" : "AFFILIATION",
             "id.token.claim" : "true",
+            "lightweight.claim" : "false",
             "access.token.claim" : "true",
-            "claim.name" : "aud",
-            "access.tokenResponse.claim" : "false"
+            "claim.name" : "affiliation",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3",
+          "name" : "given name",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "firstName",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "given_name",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88",
+          "name" : "language",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "LANGUAGE",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "language",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb",
+          "name" : "family name",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usermodel-attribute-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "user.attribute" : "lastName",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "family_name",
+            "jsonType.label" : "String"
           }
         }, {
           "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc",
@@ -1432,9 +1516,26 @@ data:
             "access.token.claim" : "true",
             "claim.name" : "uid"
           }
+        }, {
+          "id" : "c304ed2f-5952-4772-838d-91998a45f154",
+          "name" : "aud",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-hardcoded-claim-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "introspection.token.claim" : "true",
+            "claim.value" : "account",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
+            "access.token.claim" : "true",
+            "claim.name" : "aud",
+            "jsonType.label" : "String",
+            "access.tokenResponse.claim" : "false"
+          }
         } ],
-        "defaultClientScopes" : [ "roles", "attributes", "basic" ],
-        "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+        "defaultClientScopes" : [ "roles", "basic" ],
+        "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
       }, {
         "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
         "clientId" : "rabbitmq-client",
@@ -1479,12 +1580,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "false",
             "user.attribute" : "username",
             "id.token.claim" : "false",
             "access.token.claim" : "true",
             "claim.name" : "client_id",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "false"
           }
         }, {
           "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e",
@@ -1493,11 +1594,11 @@ data:
           "protocolMapper" : "oidc-hardcoded-claim-mapper",
           "consentRequired" : false,
           "config" : {
-            "claim.value" : "rabbitmq",
-            "userinfo.token.claim" : "false",
             "id.token.claim" : "false",
             "access.token.claim" : "true",
             "claim.name" : "aud",
+            "claim.value" : "rabbitmq",
+            "userinfo.token.claim" : "false",
             "access.tokenResponse.claim" : "false"
           }
         } ],
@@ -1556,8 +1657,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
           "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+",
           "pkce.code.challenge.method" : "S256"
         },
         "authenticationFlowBindingOverrides" : { },
@@ -1570,12 +1671,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "locale",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "locale",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ],
         "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
@@ -1599,8 +1700,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${emailScopeConsentText}"
+          "consent.screen.text" : "${emailScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d",
@@ -1609,12 +1710,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "emailVerified",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "email_verified",
-            "jsonType.label" : "boolean"
+            "jsonType.label" : "boolean",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3",
@@ -1623,12 +1724,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "email",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "email",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1638,8 +1739,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${profileScopeConsentText}"
+          "consent.screen.text" : "${profileScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235",
@@ -1648,12 +1749,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "username",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "preferred_username",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567",
@@ -1662,12 +1763,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "gender",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "gender",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e",
@@ -1676,12 +1777,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "birthdate",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "birthdate",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "f0e3c012-9523-4076-83ae-e466e2d08220",
@@ -1701,12 +1802,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "profile",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "profile",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3",
@@ -1715,12 +1816,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "updatedAt",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "updated_at",
-            "jsonType.label" : "long"
+            "jsonType.label" : "long",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "841ea785-26ab-429a-a420-09ce3948924d",
@@ -1729,12 +1830,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "lastName",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "family_name",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8",
@@ -1743,12 +1844,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "website",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "website",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "475f071d-5149-4379-b928-76482f5f519c",
@@ -1757,12 +1858,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "zoneinfo",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "zoneinfo",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac",
@@ -1771,12 +1872,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "middleName",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "middle_name",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "445232c8-6830-476c-a6f1-8bbef167595a",
@@ -1785,12 +1886,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "picture",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "picture",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a",
@@ -1799,12 +1900,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "locale",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "locale",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c",
@@ -1813,12 +1914,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "firstName",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "given_name",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b",
@@ -1827,12 +1928,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "nickname",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "nickname",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1866,12 +1967,12 @@ data:
           "protocolMapper" : "oidc-usermodel-property-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "username",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "upn",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1913,8 +2014,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${phoneScopeConsentText}"
+          "consent.screen.text" : "${phoneScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "dae802fb-9138-408a-b80e-a40eb0f56814",
@@ -1923,12 +2024,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "phoneNumber",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "phone_number",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "userinfo.token.claim" : "true"
           }
         }, {
           "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa",
@@ -1937,12 +2038,12 @@ data:
           "protocolMapper" : "oidc-usermodel-attribute-mapper",
           "consentRequired" : false,
           "config" : {
-            "userinfo.token.claim" : "true",
             "user.attribute" : "phoneNumberVerified",
             "id.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "phone_number_verified",
-            "jsonType.label" : "boolean"
+            "jsonType.label" : "boolean",
+            "userinfo.token.claim" : "true"
           }
         } ]
       }, {
@@ -1952,8 +2053,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "false",
-          "consent.screen.text" : ""
+          "consent.screen.text" : "",
+          "display.on.consent.screen" : "false"
         },
         "protocolMappers" : [ {
           "id" : "c6411e3b-6478-453d-b530-5fe175a4d786",
@@ -2033,6 +2134,61 @@ data:
           "gui.order" : "",
           "consent.screen.text" : ""
         }
+      }, {
+        "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6",
+        "name" : "service_account",
+        "description" : "Specific scope for a client enabled for service accounts",
+        "protocol" : "openid-connect",
+        "attributes" : {
+          "include.in.token.scope" : "false",
+          "display.on.consent.screen" : "false"
+        },
+        "protocolMappers" : [ {
+          "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512",
+          "name" : "Client IP Address",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientAddress",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientAddress",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a",
+          "name" : "Client Host",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientHost",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientHost",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae",
+          "name" : "Client ID",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "client_id",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "client_id",
+            "jsonType.label" : "String"
+          }
+        } ]
       }, {
         "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba",
         "name" : "offline_access",
@@ -2049,8 +2205,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${addressScopeConsentText}"
+          "consent.screen.text" : "${addressScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30",
@@ -2123,8 +2279,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${rolesScopeConsentText}"
+          "consent.screen.text" : "${rolesScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb",
@@ -2140,11 +2296,15 @@ data:
           "protocolMapper" : "oidc-usermodel-realm-role-mapper",
           "consentRequired" : false,
           "config" : {
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "false",
+            "multivalued" : "true",
             "user.attribute" : "foo",
+            "id.token.claim" : "true",
+            "lightweight.claim" : "false",
             "access.token.claim" : "true",
             "claim.name" : "realm_access.roles",
-            "jsonType.label" : "String",
-            "multivalued" : "true"
+            "jsonType.label" : "String"
           }
         }, {
           "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d",
@@ -2174,8 +2334,12 @@ data:
         "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
       },
       "smtpServer" : { },
+      "loginTheme" : "keycloak.v2",
+      "accountTheme" : "",
+      "adminTheme" : "",
+      "emailTheme" : "",
       "eventsEnabled" : false,
-      "eventsListeners" : [ "jboss-logging" ],
+      "eventsListeners" : [ "create-event-listener", "jboss-logging" ],
       "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
       "adminEventsEnabled" : false,
       "adminEventsDetailsEnabled" : false,
@@ -2223,7 +2387,7 @@ data:
           "subType" : "anonymous",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ]
           }
         }, {
           "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2249,7 +2413,15 @@ data:
           "subType" : "authenticated",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+          }
+        } ],
+        "org.keycloak.userprofile.UserProfileProvider" : [ {
+          "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
+          "providerId" : "declarative-user-profile",
+          "subComponents" : { },
+          "config" : {
+            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
           }
         } ],
         "org.keycloak.storage.UserStorageProvider" : [ {
@@ -2265,8 +2437,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "createTimestamp" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "read.only" : [ "true" ],
                 "always.read.value.from.ldap" : [ "true" ],
+                "read.only" : [ "true" ],
                 "user.model.attribute" : [ "createTimestamp" ]
               }
             }, {
@@ -2277,8 +2449,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "sn" ],
                 "is.mandatory.in.ldap" : [ "true" ],
-                "always.read.value.from.ldap" : [ "true" ],
                 "read.only" : [ "false" ],
+                "always.read.value.from.ldap" : [ "true" ],
                 "user.model.attribute" : [ "lastName" ]
               }
             }, {
@@ -2301,8 +2473,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "mail" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "false" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "email" ]
               }
             }, {
@@ -2311,19 +2483,19 @@ data:
               "providerId" : "group-ldap-mapper",
               "subComponents" : { },
               "config" : {
+                "mode" : [ "LDAP_ONLY" ],
                 "membership.attribute.type" : [ "DN" ],
+                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
                 "group.name.ldap.attribute" : [ "cn" ],
-                "preserve.group.inheritance" : [ "false" ],
                 "membership.user.ldap.attribute" : [ "uid" ],
-                "groups.dn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ],
-                "mode" : [ "LDAP_ONLY" ],
-                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
-                "membership.ldap.attribute" : [ "member" ],
                 "ignore.missing.groups" : [ "false" ],
+                "preserve.group.inheritance" : [ "false" ],
+                "membership.ldap.attribute" : [ "member" ],
                 "memberof.ldap.attribute" : [ "memberOf" ],
                 "group.object.classes" : [ "groupOfNames" ],
-                "drop.non.existing.groups.during.sync" : [ "false" ],
-                "groups.path" : [ "/" ]
+                "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
+                "groups.path" : [ "/" ],
+                "drop.non.existing.groups.during.sync" : [ "false" ]
               }
             }, {
               "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb",
@@ -2347,15 +2519,15 @@ data:
                 "is.mandatory.in.ldap" : [ "true" ],
                 "attribute.force.default" : [ "false" ],
                 "is.binary.attribute" : [ "false" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "false" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "username" ]
               }
             } ]
           },
           "config" : {
-            "pagination" : [ "false" ],
             "fullSyncPeriod" : [ "-1" ],
+            "pagination" : [ "false" ],
             "startTls" : [ "false" ],
             "connectionPooling" : [ "true" ],
             "usersDn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ],
@@ -2363,15 +2535,15 @@ data:
             "useKerberosForPasswordAuthentication" : [ "false" ],
             "importEnabled" : [ "true" ],
             "enabled" : [ "true" ],
+            "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ],
             "changedSyncPeriod" : [ "-1" ],
-            "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ],
             "usernameLDAPAttribute" : [ "uid" ],
-            "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ],
+            "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ],
             "lastSync" : [ "1719252666" ],
             "vendor" : [ "other" ],
             "uuidLDAPAttribute" : [ "entryUUID" ],
-            "connectionUrl" : [ "ldap://identity-service:389" ],
             "allowKerberosAuthentication" : [ "false" ],
+            "connectionUrl" : [ "ldap://identity-service:389" ],
             "syncRegistrations" : [ "true" ],
             "authType" : [ "simple" ],
             "useTruststoreSpi" : [ "always" ],
@@ -2383,14 +2555,6 @@ data:
             "validatePasswordPolicy" : [ "false" ]
           }
         } ],
-        "org.keycloak.userprofile.UserProfileProvider" : [ {
-          "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43",
-          "providerId" : "declarative-user-profile",
-          "subComponents" : { },
-          "config" : {
-            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ]
-          }
-        } ],
         "org.keycloak.keys.KeyProvider" : [ {
           "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51",
           "name" : "rsa-enc-generated",
@@ -3003,10 +3167,12 @@ data:
         "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "",
         "parRequestUriLifespan" : "60",
         "clientSessionMaxLifespan" : "0",
+        "organizationsEnabled" : "false",
         "shortVerificationUri" : ""
       },
-      "keycloakVersion" : "24.0.5",
+      "keycloakVersion" : "26.0.4",
       "userManagedAccessAllowed" : false,
+      "organizationsEnabled" : false,
       "clientProfiles" : {
         "profiles" : [ ]
       },
@@ -3014,7 +3180,7 @@ data:
         "policies" : [ ]
       }
     }
-  master-realm.json: |
+  master-realm.json: |-
     {
       "id" : "afe47bd0-61f8-40c3-95cb-04930407ebdd",
       "realm" : "master",
@@ -3057,6 +3223,7 @@ data:
       "bruteForceProtected" : false,
       "permanentLockout" : false,
       "maxTemporaryLockouts" : 0,
+      "bruteForceStrategy" : "MULTIPLE",
       "maxFailureWaitSeconds" : 900,
       "minimumQuickLoginWaitSeconds" : 60,
       "waitIncrementSeconds" : 60,
@@ -3681,8 +3848,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
-          "client.use.lightweight.access.token.enabled" : "true"
+          "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+"
         },
         "authenticationFlowBindingOverrides" : { },
         "fullScopeAllowed" : true,
@@ -3800,8 +3967,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "realm_client" : "false",
-          "post.logout.redirect.uris" : "+",
           "client.use.lightweight.access.token.enabled" : "true",
+          "post.logout.redirect.uris" : "+",
           "pkce.code.challenge.method" : "S256"
         },
         "authenticationFlowBindingOverrides" : { },
@@ -3833,8 +4000,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${addressScopeConsentText}"
+          "consent.screen.text" : "${addressScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "4aed5e41-0d8d-4c24-80a0-cd9822072756",
@@ -3862,8 +4029,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${organizationScopeConsentText}"
+          "consent.screen.text" : "${organizationScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "5e80a7d2-c9d0-48e1-aadc-d8848ff90f92",
@@ -3881,6 +4048,61 @@ data:
             "jsonType.label" : "String"
           }
         } ]
+      }, {
+        "id" : "1be1e284-2749-4bbb-890a-2d519cc1531c",
+        "name" : "service_account",
+        "description" : "Specific scope for a client enabled for service accounts",
+        "protocol" : "openid-connect",
+        "attributes" : {
+          "include.in.token.scope" : "false",
+          "display.on.consent.screen" : "false"
+        },
+        "protocolMappers" : [ {
+          "id" : "c913a673-cf66-4493-a2ed-14556c07617c",
+          "name" : "Client ID",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "client_id",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "client_id",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "5c244d68-5c63-4356-ac71-5a586f40c77e",
+          "name" : "Client IP Address",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientAddress",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientAddress",
+            "jsonType.label" : "String"
+          }
+        }, {
+          "id" : "600285d4-ae51-4b39-a7be-bb83cf5870db",
+          "name" : "Client Host",
+          "protocol" : "openid-connect",
+          "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+          "consentRequired" : false,
+          "config" : {
+            "user.session.note" : "clientHost",
+            "introspection.token.claim" : "true",
+            "userinfo.token.claim" : "true",
+            "id.token.claim" : "true",
+            "access.token.claim" : "true",
+            "claim.name" : "clientHost",
+            "jsonType.label" : "String"
+          }
+        } ]
       }, {
         "id" : "0411ea86-a074-4781-850d-ea3ca94590a2",
         "name" : "offline_access",
@@ -3932,8 +4154,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${profileScopeConsentText}"
+          "consent.screen.text" : "${profileScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "2d1400be-4053-4393-ba87-91b64f699054",
@@ -4234,8 +4456,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "false",
-          "consent.screen.text" : ""
+          "consent.screen.text" : "",
+          "display.on.consent.screen" : "false"
         },
         "protocolMappers" : [ {
           "id" : "635cbac1-7cab-43bd-99fc-f7084aca2fa2",
@@ -4271,8 +4493,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "false",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${rolesScopeConsentText}"
+          "consent.screen.text" : "${rolesScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "2b5a3df4-1adb-402d-bc28-2bd43224e682",
@@ -4281,12 +4503,12 @@ data:
           "protocolMapper" : "oidc-usermodel-realm-role-mapper",
           "consentRequired" : false,
           "config" : {
-            "introspection.token.claim" : "true",
-            "multivalued" : "true",
             "user.attribute" : "foo",
+            "introspection.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "realm_access.roles",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "multivalued" : "true"
           }
         }, {
           "id" : "f3b60071-ef26-48a7-9554-67f62f84d543",
@@ -4295,12 +4517,12 @@ data:
           "protocolMapper" : "oidc-usermodel-client-role-mapper",
           "consentRequired" : false,
           "config" : {
-            "introspection.token.claim" : "true",
-            "multivalued" : "true",
             "user.attribute" : "foo",
+            "introspection.token.claim" : "true",
             "access.token.claim" : "true",
             "claim.name" : "resource_access.${client_id}.roles",
-            "jsonType.label" : "String"
+            "jsonType.label" : "String",
+            "multivalued" : "true"
           }
         }, {
           "id" : "b757200e-494a-4585-857e-e4c18aef7a0c",
@@ -4320,8 +4542,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${emailScopeConsentText}"
+          "consent.screen.text" : "${emailScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "e18769b3-778b-47d8-be52-dd2769deebd1",
@@ -4361,8 +4583,8 @@ data:
         "protocol" : "openid-connect",
         "attributes" : {
           "include.in.token.scope" : "true",
-          "display.on.consent.screen" : "true",
-          "consent.screen.text" : "${phoneScopeConsentText}"
+          "consent.screen.text" : "${phoneScopeConsentText}",
+          "display.on.consent.screen" : "true"
         },
         "protocolMappers" : [ {
           "id" : "98cc724c-3f53-47f7-bf9f-baf2f7e08026",
@@ -4448,7 +4670,7 @@ data:
           "subType" : "anonymous",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-user-property-mapper" ]
           }
         }, {
           "id" : "4b976576-c880-48a0-9b4d-2956cfd19b4a",
@@ -4457,7 +4679,7 @@ data:
           "subType" : "authenticated",
           "subComponents" : { },
           "config" : {
-            "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ]
+            "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper" ]
           }
         }, {
           "id" : "e1861ec9-2761-46fb-8048-149492269ff0",
@@ -4487,6 +4709,14 @@ data:
             "allow-default-scopes" : [ "true" ]
           }
         } ],
+        "org.keycloak.userprofile.UserProfileProvider" : [ {
+          "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
+          "providerId" : "declarative-user-profile",
+          "subComponents" : { },
+          "config" : {
+            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
+          }
+        } ],
         "org.keycloak.storage.UserStorageProvider" : [ {
           "id" : "3a6f24e8-128b-4ac1-b3ab-694836db82fd",
           "name" : "Identity Service",
@@ -4500,8 +4730,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "mail" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "false" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "email" ]
               }
             }, {
@@ -4512,8 +4742,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "sn" ],
                 "is.mandatory.in.ldap" : [ "true" ],
-                "read.only" : [ "false" ],
                 "always.read.value.from.ldap" : [ "true" ],
+                "read.only" : [ "false" ],
                 "user.model.attribute" : [ "lastName" ]
               }
             }, {
@@ -4524,8 +4754,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "modifyTimestamp" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "always.read.value.from.ldap" : [ "true" ],
                 "read.only" : [ "true" ],
+                "always.read.value.from.ldap" : [ "true" ],
                 "user.model.attribute" : [ "modifyTimestamp" ]
               }
             }, {
@@ -4558,17 +4788,17 @@ data:
               "providerId" : "group-ldap-mapper",
               "subComponents" : { },
               "config" : {
+                "mode" : [ "LDAP_ONLY" ],
                 "membership.attribute.type" : [ "DN" ],
+                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
                 "group.name.ldap.attribute" : [ "cn" ],
+                "ignore.missing.groups" : [ "false" ],
                 "membership.user.ldap.attribute" : [ "uid" ],
                 "preserve.group.inheritance" : [ "false" ],
-                "groups.dn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ],
-                "mode" : [ "LDAP_ONLY" ],
-                "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ],
                 "membership.ldap.attribute" : [ "member" ],
-                "ignore.missing.groups" : [ "false" ],
-                "group.object.classes" : [ "groupOfNames" ],
+                "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ],
                 "memberof.ldap.attribute" : [ "memberOf" ],
+                "group.object.classes" : [ "groupOfNames" ],
                 "drop.non.existing.groups.during.sync" : [ "false" ],
                 "groups.path" : [ "/" ]
               }
@@ -4580,8 +4810,8 @@ data:
               "config" : {
                 "ldap.attribute" : [ "createTimestamp" ],
                 "is.mandatory.in.ldap" : [ "false" ],
-                "always.read.value.from.ldap" : [ "true" ],
                 "read.only" : [ "true" ],
+                "always.read.value.from.ldap" : [ "true" ],
                 "user.model.attribute" : [ "createTimestamp" ]
               }
             } ]
@@ -4597,13 +4827,13 @@ data:
             "importEnabled" : [ "true" ],
             "enabled" : [ "true" ],
             "changedSyncPeriod" : [ "-1" ],
+            "usernameLDAPAttribute" : [ "uid" ],
             "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ],
             "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ],
-            "usernameLDAPAttribute" : [ "uid" ],
             "vendor" : [ "other" ],
             "uuidLDAPAttribute" : [ "entryUUID" ],
             "allowKerberosAuthentication" : [ "false" ],
-            "connectionUrl" : [ "ldap://identity-service:1389" ],
+            "connectionUrl" : [ "ldap://identity-service:389" ],
             "syncRegistrations" : [ "true" ],
             "authType" : [ "simple" ],
             "krbPrincipalAttribute" : [ "krb5PrincipalName" ],
@@ -4617,14 +4847,6 @@ data:
             "validatePasswordPolicy" : [ "false" ]
           }
         } ],
-        "org.keycloak.userprofile.UserProfileProvider" : [ {
-          "id" : "34049725-5a66-456c-b895-87ca7c11bb6b",
-          "providerId" : "declarative-user-profile",
-          "subComponents" : { },
-          "config" : {
-            "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ]
-          }
-        } ],
         "org.keycloak.keys.KeyProvider" : [ {
           "id" : "5b1052d2-fb71-47d2-86f9-908c869c8d1b",
           "name" : "hmac-generated-hs512",
@@ -5236,10 +5458,12 @@ data:
         "parRequestUriLifespan" : "60",
         "clientSessionMaxLifespan" : "0",
         "frontendUrl" : "",
+        "organizationsEnabled" : "false",
         "acr.loa.map" : "{}"
       },
-      "keycloakVersion" : "24.0.5",
+      "keycloakVersion" : "26.0.4",
       "userManagedAccessAllowed" : false,
+      "organizationsEnabled" : false,
       "clientProfiles" : {
         "profiles" : [ ]
       },
diff --git a/helm/dbrepo/templates/auth-secret.yaml b/helm/dbrepo/templates/auth-secret.yaml
index a568ef25007e51d70bf4ad1ac186645e57499015..dca0f861f132ea1557a52b488c63e74e6b435917 100644
--- a/helm/dbrepo/templates/auth-secret.yaml
+++ b/helm/dbrepo/templates/auth-secret.yaml
@@ -11,6 +11,8 @@ stringData:
   AUTH_SERVICE_ENDPOINT: "{{ .Values.authservice.endpoint }}"
   METADATA_DB: "{{ .Values.metadatadb.db.name }}"
   METADATA_DB_PASSWORD: "{{ .Values.metadatadb.rootUser.password }}"
+  METADATA_SERVICE_ENDPOINT: "{{ .Values.metadataservice.endpoint }}/api/user"
   METADATA_USERNAME: "{{ .Values.metadatadb.rootUser.user }}"
   SYSTEM_USERNAME: "{{ .Values.identityservice.users }}"
+  SYSTEM_PASSWORD: "{{ .Values.identityservice.userPasswords }}"
 {{- end }}
diff --git a/helm/dbrepo/templates/gateway-configmap.yaml b/helm/dbrepo/templates/gateway-configmap.yaml
index aa314d3c65948076a4e7eaf977bf47b8735b153d..8ef358871523c80ac16ec128e54e116b3d57d52e 100644
--- a/helm/dbrepo/templates/gateway-configmap.yaml
+++ b/helm/dbrepo/templates/gateway-configmap.yaml
@@ -39,6 +39,24 @@ data:
             proxy_read_timeout      90;
         }
 
+        location /realms {
+            proxy_set_header        Host $host;
+            proxy_set_header        X-Real-IP $remote_addr;
+            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header        X-Forwarded-Proto $scheme;
+            proxy_pass              https://auth-service;
+            proxy_read_timeout      90;
+        }
+
+        location /resources {
+            proxy_set_header        Host $host;
+            proxy_set_header        X-Real-IP $remote_addr;
+            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header        X-Forwarded-Proto $scheme;
+            proxy_pass              https://auth-service;
+            proxy_read_timeout      90;
+        }
+
         location /api/search {
             proxy_set_header        Host $host;
             proxy_set_header        X-Real-IP $remote_addr;
diff --git a/helm/dbrepo/templates/ui-secret.yaml b/helm/dbrepo/templates/ui-secret.yaml
index 5620e7b2da88226759723c4bbd24f2e5479bc444..a84ac8f5cef024c88fa41ce085f494cca396df9f 100644
--- a/helm/dbrepo/templates/ui-secret.yaml
+++ b/helm/dbrepo/templates/ui-secret.yaml
@@ -22,4 +22,13 @@ stringData:
   NUXT_PUBLIC_PID_DEFAULT_PUBLISHER: "{{ .Values.ui.public.pid.default.publisher }}"
   NUXT_PUBLIC_UPLOAD_CLIENT: "{{ .Values.ui.public.upload.client | default $uploadEndpoint }}"
   NUXT_PUBLIC_BROKER_CONNECTIONS: "{{ include "dbrepo.broker.connections" . }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/auth"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_BASE_URL: "{{ .Values.gateway }}/realms/dbrepo"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "{{ .Values.authservice.client.id }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "{{ .Values.authservice.client.secret }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "{{ .Values.gateway }}"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/logout"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "{{ .Values.gateway }}/auth/keycloak/callback"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/token"
+  NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/userinfo"
 {{- end }}
diff --git a/helm/dbrepo/values.schema.json b/helm/dbrepo/values.schema.json
index 9ade1b07493e1aa92d11a726d38f869b4ad69461..641287b434aff0bf533a2416081a9d6c0e447742 100644
--- a/helm/dbrepo/values.schema.json
+++ b/helm/dbrepo/values.schema.json
@@ -126,7 +126,7 @@
                 "endpoint": {
                     "type": "string"
                 },
-                "extraEnvVarsCM": {
+                "extraEnvVarsSecret": {
                     "type": "string"
                 },
                 "extraVolumeMounts": {
@@ -137,6 +137,9 @@
                             },
                             "name": {
                                 "type": "string"
+                            },
+                            "subPath": {
+                                "type": "string"
                             }
                         },
                         "type": "object"
@@ -224,6 +227,9 @@
                     },
                     "type": "object"
                 },
+                "production": {
+                    "type": "boolean"
+                },
                 "replicaCount": {
                     "type": "integer"
                 },
diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml
index 84cf7b5dddb964fa107f496b6c41d5bbcdfff34c..7515778b33d38b5e427a85742d5aa0d71b9e6a3a 100644
--- a/helm/dbrepo/values.yaml
+++ b/helm/dbrepo/values.yaml
@@ -87,6 +87,8 @@ authservice:
     fullnameOverride: auth-db
     auth:
       postgresPassword: postgres
+  ## @param authservice.production Start Keycloak with production profile.
+  production: true
   ## @param authservice.resourcesPreset The container resource presets
   resourcesPreset: "small"
   jwt:
@@ -116,7 +118,7 @@ authservice:
   setupJob:
     image:
       ## @skip authservice.setupJob.image.name
-      name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.2
+      name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.3
     ## @param authservice.setupJob.resourcesPreset The container resource preset
     resourcesPreset: "nano"
     ## @param authservice.setupJob.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads)
@@ -127,8 +129,8 @@ authservice:
     ##   limits:
     ##     cpu: 500m
     ##     memory: 1024Mi
-  ## @skip authservice.extraEnvVarsCM
-  extraEnvVarsCM: auth-service-config
+  ## @skip authservice.extraEnvVarsSecret
+  extraEnvVarsSecret: auth-service-secret
   ## @skip authservice.extraVolumes
   extraVolumes:
     - name: config-map
@@ -140,7 +142,14 @@ authservice:
   ## @skip authservice.extraVolumeMounts
   extraVolumeMounts:
     - name: config-map
-      mountPath: /opt/keycloak/data/import
+      mountPath: /opt/keycloak/data/import/dbrepo-realm.json
+      subPath: dbrepo-realm.json
+    - name: config-map
+      mountPath: /opt/keycloak/data/import/master-realm.json
+      subPath: master-realm.json
+    - name: config-map
+      mountPath: /opt/bitnami/keycloak/providers/create-event-listener.jar
+      subPath: create-event-listener.jar
     - name: cache
       mountPath: /bitnami/keycloak/
   ## @skip authservice.replicaCount The number of replicas.
@@ -392,7 +401,7 @@ analyseservice:
   enabled: true
   image:
     ## @skip analyseservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.2
+    name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param analyseservice.podSecurityContext.enabled Enable pods' Security Context
@@ -453,7 +462,7 @@ metadataservice:
   enabled: true
   image:
     ## @skip metadataservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.2
+    name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param metadataservice.podSecurityContext.enabled Enable pods' Security Context
@@ -550,7 +559,7 @@ dataservice:
   endpoint: http://data-service
   image:
     ## @skip dataservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.2
+    name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param dataservice.podSecurityContext.enabled Enable pods' Security Context
@@ -636,7 +645,7 @@ searchservice:
   endpoint: http://search-service
   image:
     ## @skip searchservice.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.2
+    name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param searchservice.podSecurityContext.enabled Enable pods' Security Context
@@ -683,7 +692,7 @@ searchservice:
   init:
     image:
       ## @skip searchservice.init.image.name
-      name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.2
+      name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3
     ## @param searchservice.init.resourcesPreset The container resource preset
     resourcesPreset: "nano"
     ## @param searchservice.init.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads)
@@ -744,7 +753,7 @@ storageservice:
   init:
     image:
       ## @skip storageservice.init.image.name
-      name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.2
+      name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3
     s3:
       ## @param storageservice.init.s3.endpoint The S3-capable endpoint the microservice connects to.
       endpoint: http://storage-service-s3:8333
@@ -853,7 +862,7 @@ ui:
   enabled: true
   image:
     ## @skip ui.image.name
-    name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.2
+    name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3
   ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
   podSecurityContext:
     ## @param ui.podSecurityContext.enabled Enable pods' Security Context
@@ -941,7 +950,7 @@ ui:
       ## @param ui.public.doi.endpoint The DOI proxy.
       endpoint: https://doi.org
   ## @param ui.replicaCount The number of replicas.
-  replicaCount: 2
+  replicaCount: 1
   ## @skip ui.extraVolumes
   extraVolumes: [ ]
   #  - name: images-map
diff --git a/helm/seaweedfs/Chart.lock b/helm/seaweedfs/Chart.lock
index edcc38c41f0c6b2b35f8d740566918ddb16f17fc..96e5c8dce913d2f7a73bf8adc5d7f121fb2a3b70 100644
--- a/helm/seaweedfs/Chart.lock
+++ b/helm/seaweedfs/Chart.lock
@@ -1,12 +1,12 @@
 dependencies:
 - name: mariadb
   repository: oci://registry-1.docker.io/bitnamicharts
-  version: 20.2.1
+  version: 20.2.2
 - name: postgresql
   repository: oci://registry-1.docker.io/bitnamicharts
-  version: 16.4.3
+  version: 16.4.6
 - name: common
   repository: oci://registry-1.docker.io/bitnamicharts
-  version: 2.29.0
-digest: sha256:4c967f771b303ca0db9ba2e355790152448c77a05d3f6c69eda6c234bc3f60c6
-generated: "2025-01-17T15:24:18.141765362+01:00"
+  version: 2.29.1
+digest: sha256:bc14ae7bbe7be291adc4a6329ae64835c367b09277a2678c4e10cc74b19ee491
+generated: "2025-02-04T22:22:11.88596441+01:00"
diff --git a/helm/seaweedfs/charts/common-2.29.0.tgz b/helm/seaweedfs/charts/common-2.29.0.tgz
deleted file mode 100644
index f36e9e24ec32ce1237d1ee774541c5586fce222d..0000000000000000000000000000000000000000
Binary files a/helm/seaweedfs/charts/common-2.29.0.tgz and /dev/null differ
diff --git a/helm/seaweedfs/charts/common-2.29.1.tgz b/helm/seaweedfs/charts/common-2.29.1.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..8b9abbbc5b6c62a743cc0fb041d26b199c4313c8
Binary files /dev/null and b/helm/seaweedfs/charts/common-2.29.1.tgz differ
diff --git a/helm/seaweedfs/charts/mariadb-20.2.1.tgz b/helm/seaweedfs/charts/mariadb-20.2.1.tgz
deleted file mode 100644
index 9bba8eed49e866977396c0076b1a9c5946ec88b1..0000000000000000000000000000000000000000
Binary files a/helm/seaweedfs/charts/mariadb-20.2.1.tgz and /dev/null differ
diff --git a/helm/seaweedfs/charts/mariadb-20.2.2.tgz b/helm/seaweedfs/charts/mariadb-20.2.2.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..a983469f30dfce693288215705891f387c517319
Binary files /dev/null and b/helm/seaweedfs/charts/mariadb-20.2.2.tgz differ
diff --git a/helm/seaweedfs/charts/postgresql-16.4.3.tgz b/helm/seaweedfs/charts/postgresql-16.4.3.tgz
deleted file mode 100644
index 429f7ed063f6655796792fbe711b027e147ddda4..0000000000000000000000000000000000000000
Binary files a/helm/seaweedfs/charts/postgresql-16.4.3.tgz and /dev/null differ
diff --git a/helm/seaweedfs/charts/postgresql-16.4.6.tgz b/helm/seaweedfs/charts/postgresql-16.4.6.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..9016ba352dfd2b553e3cac4a8a80fb7c8c539d65
Binary files /dev/null and b/helm/seaweedfs/charts/postgresql-16.4.6.tgz differ
diff --git a/install.sh b/install.sh
index 3ccfd30b2162c145bac392457b5ceccc7f7d81eb..fa48d9bc35c83375ca02c9810b7e6a0ee780af21 100644
--- a/install.sh
+++ b/install.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # preset
-VERSION="1.6.2"
+VERSION="1.6.3"
 MIN_CPU=8
 MIN_RAM=4
 MIN_MAP_COUNT=262144
diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py
index 50cd161bc300e249e7cb904a055e4f8d7390e818..bd0d13dc1894d1a83891abdcdd6fb438de27f3f4 100644
--- a/lib/python/dbrepo/api/dto.py
+++ b/lib/python/dbrepo/api/dto.py
@@ -124,7 +124,7 @@ class TableBrief(BaseModel):
     id: int
     database_id: int
     name: str
-    description: Optional[str]
+    description: Optional[str] = None
     internal_name: str
     is_versioned: bool
     is_public: bool
diff --git a/lib/python/docs/index.rst b/lib/python/docs/index.rst
index 13561e9c13dd7f78798aca5b5e9e7162f309a7c2..b3c05fe3645e558aaa92a470c19be4d27db46add 100644
--- a/lib/python/docs/index.rst
+++ b/lib/python/docs/index.rst
@@ -6,7 +6,7 @@ Pandas `DataFrame <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame
 provides an object-oriented API as well as low-level access to DBRepo services.
 
 .. note::
-   The SDK has been implemented and documented for DBRepo version 1.6.2, earlier versions may be supported but are not tested for compatibility.
+   The SDK has been implemented and documented for DBRepo version 1.6.3, earlier versions may be supported but are not tested for compatibility.
 
 Quickstart
 ----------
diff --git a/lib/python/pyproject.toml b/lib/python/pyproject.toml
index 5b8deb84080301d7d2eaa2738c2e30b43a4ecca0..99f62c9a44dcdb10f63d03c97048a0676a1b1d02 100644
--- a/lib/python/pyproject.toml
+++ b/lib/python/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = "dbrepo"
-version = "1.6.2"
+version = "1.6.3"
 description = "DBRepo Python Library"
 keywords = [
     "DBRepo",
diff --git a/lib/python/setup.py b/lib/python/setup.py
index c6deff531d7840f390eb16936af94cff9f9fa622..dfe9a897cab556846dbf7dfb6ffb5303d0e77b03 100644
--- a/lib/python/setup.py
+++ b/lib/python/setup.py
@@ -2,7 +2,7 @@
 from distutils.core import setup
 
 setup(name="dbrepo",
-      version="1.6.2",
+      version="1.6.3",
       description="A library for communicating with DBRepo",
       url="https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/",
       author="Martin Weise",
diff --git a/make/build.mk b/make/build.mk
index bc6dfc56a7421b53c6ad02f5bd4518f5f6b614ab..270b2cee6fd80b9dea9a475399081ae34ad65c91 100644
--- a/make/build.mk
+++ b/make/build.mk
@@ -14,23 +14,27 @@ build-data-service: ## Build the Data Service.
 build-metadata-service: ## Build the Metadata Service.
 	mvn -f ./dbrepo-metadata-service/pom.xml clean package -DskipTests
 
+.PHONY: build-auth-event-listener
+build-auth-event-listener: ## Build the Auth Service Event Listener.
+	mvn -f ./dbrepo-auth-service/listeners/pom.xml clean package -DskipTests
+
 .PHONY: build-ui
 build-ui: ## Build the UI.
 	bun --cwd ./dbrepo-ui build
 
 .PHONY: build-lib
 build-lib: ## Build the Python Library.
-	rm -f ./dbrepo-analyse-service/Pipfile.lock ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}*
-	rm -f ./dbrepo-search-service/Pipfile.lock ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}*
-	rm -f ./dbrepo-search-service/init/Pipfile.lock ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}*
+	rm -rf ./dbrepo-analyse-service/venv/ ./dbrepo-analyse-service/Pipfile.lock ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}*
+	rm -rf ./dbrepo-search-service/venv/ ./dbrepo-search-service/Pipfile.lock ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}*
+	rm -rf ./dbrepo-search-service/init/venv/ ./dbrepo-search-service/init/Pipfile.lock ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}*
 	python3 -m build --sdist ./lib/python
 	python3 -m build --wheel ./lib/python
 	cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-analyse-service/lib
-	(cd ./dbrepo-analyse-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock)
+	(cd ./dbrepo-analyse-service && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev)
 	cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-search-service/lib
-	(cd ./dbrepo-search-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock)
+	(cd ./dbrepo-search-service && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev)
 	cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-search-service/init/lib
-	(cd ./dbrepo-search-service/init && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock)
+	(cd ./dbrepo-search-service/init && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev)
 
 .PHONY: build-helm
 build-helm: ## Build the DBRepo and DBRepo MariaDB Galera Helm Charts.
diff --git a/make/dev.mk b/make/dev.mk
index 0282dbbce287356e207822fdc9dbf1be7e26e0b8..d8da31086b3dfcba7f85aeeaa6db64564b87c036 100644
--- a/make/dev.mk
+++ b/make/dev.mk
@@ -1,7 +1,7 @@
 ##@ Development
 
 .PHONY: start-dev
-start-dev: build-images ## Start the development deployment.
+start-dev: build-images build-auth-event-listener ## Start the development deployment.
 	docker container stop dbrepo-gateway-service || true
 	docker container rm dbrepo-gateway-service || true
 	docker compose up -d
diff --git a/sonar-project.properties b/sonar-project.properties
index 83f00a3a2497898a97eaf0d12851ce7ab9383709..4442bf46ff84667faa8f20672f21d14be29fef3e 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -2,7 +2,7 @@
 sonar.projectKey=fair-data-austria-db-repository_fda-services_a57fa043-ab99-4cdd-a721-162d9a916d77
 sonar.host.url=https://s39.datalab.tuwien.ac.at
 # project
-sonar.projectVersion=1.6.2
+sonar.projectVersion=1.6.3
 # general
 sonar.qualitygate.wait=true
 sonar.projectCreation.mainBranchName=master