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/OntologiesList.vue b/dbrepo-ui/components/OntologiesList.vue
index c7120cac4a1e58e4a1f22c651f77aebcaf002584..432d26e428eed1085d2806ed371342b445822599 100644
--- a/dbrepo-ui/components/OntologiesList.vue
+++ b/dbrepo-ui/components/OntologiesList.vue
@@ -34,29 +34,20 @@
   </div>
 </template>
 
+<script setup>
+</script>
 <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
+      return []
     }
   },
   mounted () {
diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue
index 4177ae592cbae97090d0b109c576137b0ee74cbc..9d43b262e3c3b67cfe748fcb13168d17362af1d0 100644
--- a/dbrepo-ui/components/database/DatabaseToolbar.vue
+++ b/dbrepo-ui/components/database/DatabaseToolbar.vue
@@ -81,9 +81,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import { useCacheStore } from '@/stores/cache.js'
-import { useUserStore } from '@/stores/user.js'
 import ResourceStatus from '@/components/ResourceStatus.vue'
 
 export default {
@@ -94,8 +100,7 @@ export default {
     return {
       tab: null,
       error: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -103,13 +108,7 @@ 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
     },
     isContrastTheme () {
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast')
@@ -172,7 +171,7 @@ export default {
       if (!this.database || !this.user) {
         return false
       }
-      return this.database.owner.username === this.user.username
+      return this.database.owner.id === this.userInfo.uid
     },
     buttonVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue
index 3dba450e634c6db374ccd28bd327ff2823756f3e..408d7e8265b667a6f1ab2b8a8e5c966bfa8e7028 100644
--- a/dbrepo-ui/components/identifier/Persist.vue
+++ b/dbrepo-ui/components/identifier/Persist.vue
@@ -827,10 +827,16 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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,17 +968,10 @@ export default {
         { value: 'IsObsoletedBy' },
         { value: 'Obsoletes' }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     isSubset () {
       return this.type === 'subset'
     },
@@ -1045,9 +1044,6 @@ export default {
           }
       }
     },
-    isUpdate () {
-      return 'id' in this.identifier && this.identifier.id
-    },
     canInsertSelf () {
       if (!this.user) {
         return false
diff --git a/dbrepo-ui/components/identifier/Select.vue b/dbrepo-ui/components/identifier/Select.vue
index 4404a09635c6833e609f74c4f685988550dc97c8..84f87e321fcb81c7d7e233cedd4a79ad45b21271 100644
--- a/dbrepo-ui/components/identifier/Select.vue
+++ b/dbrepo-ui/components/identifier/Select.vue
@@ -41,10 +41,16 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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 {
@@ -68,17 +74,10 @@ export default {
   data () {
     return {
       idx: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     displayIdentifiers () {
       if (!this.identifiers) {
         return []
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..ae7df2768370f472a85c1dd5cbe673773c92cac1 100644
--- a/dbrepo-ui/components/subset/Builder.vue
+++ b/dbrepo-ui/components/subset/Builder.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="loggedIn">
     <v-toolbar flat>
       <v-btn
         size="small"
@@ -303,12 +304,16 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+</script>
 <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 {
@@ -359,8 +364,7 @@ export default {
       tabs: 0,
       loadingQuery: false,
       loadingColumns: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -388,9 +392,6 @@ export default {
       }
       return this.database.container.image.data_types
     },
-    user () {
-      return this.userStore.getUser
-    },
     viewNames () {
       if (!this.database) {
         return []
diff --git a/dbrepo-ui/components/subset/SubsetList.vue b/dbrepo-ui/components/subset/SubsetList.vue
index 6908b2b4381d88d7b5a7a19ce540b4c88c633e0e..eb6a27aacda5ba99b16fa920ccc08594f8ccea92 100644
--- a/dbrepo-ui/components/subset/SubsetList.vue
+++ b/dbrepo-ui/components/subset/SubsetList.vue
@@ -45,8 +45,6 @@
 </template>
 
 <script>
-import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -55,14 +53,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 +124,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..45ca7626289965f57d5771afaed4c1159fd0f414 100644
--- a/dbrepo-ui/components/subset/SubsetToolbar.vue
+++ b/dbrepo-ui/components/subset/SubsetToolbar.vue
@@ -55,10 +55,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+</script>
 <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 +76,6 @@ export default {
       loading: false,
       loadingSave: false,
       downloadLoading: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -86,13 +90,7 @@ 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
@@ -154,10 +152,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.userInfo || !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.userInfo.uid || (this.subset.owner.id === this.userInfo.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..d34483422d232292b6d108a3a5aa4a13e4a16ac4 100644
--- a/dbrepo-ui/components/table/TableList.vue
+++ b/dbrepo-ui/components/table/TableList.vue
@@ -38,9 +38,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import { formatTimestampUTCLabel } from '@/utils'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -74,19 +80,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..9aee22348ffc55c1b11c385592f685314a7b5e20 100644
--- a/dbrepo-ui/components/table/TableToolbar.vue
+++ b/dbrepo-ui/components/table/TableToolbar.vue
@@ -77,10 +77,16 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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 +99,7 @@ export default {
       error: false,
       edit: false,
       dropTableDialog: false,
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
@@ -105,7 +110,7 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
@@ -113,17 +118,11 @@ export default {
       }
       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
-    },
     canUpdateTable () {
       if (!this.roles || !this.user || !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.userInfo.uid
     },
     canExecuteQuery () {
       if (!this.roles || !this.table || !this.user) {
@@ -149,7 +148,7 @@ export default {
       if (!this.user) {
         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.userInfo.uid || this.database.owner.id === this.userInfo.uid
     },
     canViewSchema () {
       if (!this.table) {
@@ -161,7 +160,7 @@ export default {
       if (!this.user) {
         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.userInfo.uid || this.database.owner.id === this.userInfo.uid
     },
     canImportCsv () {
       if (!this.roles || !this.table || !this.user) {
@@ -173,7 +172,7 @@ export default {
       if (!this.user || !this.table || !this.database) {
         return false
       }
-      return this.database.owner.id === this.user.id || this.table.owner.id === this.user.id
+      return this.database.owner.id === this.userInfo.uid || this.table.owner.id === this.userInfo.uid
     },
     buttonVariant () {
       const runtimeConfig = useRuntimeConfig()
diff --git a/dbrepo-ui/components/user/UserToolbar.vue b/dbrepo-ui/components/user/UserToolbar.vue
index e5a20c75a3230d80dc3e6f63c27c5bb6a743a463..868bab88a94123ae28aa2702f543ddab3f54dc0d 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, user, login, logout } = 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..58038b7a82f038aeebef4e7a70e684cccab51449 100644
--- a/dbrepo-ui/components/view/ViewList.vue
+++ b/dbrepo-ui/components/view/ViewList.vue
@@ -34,7 +34,6 @@
 </template>
 
 <script>
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -43,14 +42,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..74eac9dedf5d7e446585dd01a5e5e4a107f1ae29 100644
--- a/dbrepo-ui/components/view/ViewToolbar.vue
+++ b/dbrepo-ui/components/view/ViewToolbar.vue
@@ -56,8 +56,14 @@
   </v-toolbar>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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 +79,6 @@ export default {
       loading: false,
       loadingDelete: false,
       updateViewDialog: false,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -101,7 +106,7 @@ export default {
       if (!this.user) {
         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.userInfo.id || this.database.owner.id === this.userInfo.id
     },
     canViewSchema () {
       if (!this.view) {
@@ -113,13 +118,13 @@ export default {
       if (!this.user) {
         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.userInfo.id || this.database.owner.id === this.userInfo.id
     },
     canViewSettings () {
       if (!this.user || !this.view) {
         return false
       }
-      return this.view.owner.id === this.user.id
+      return this.view.owner.id === this.userInfo.id
     },
     canCreatePid () {
       if (!this.roles || !this.user || !this.view) {
@@ -129,13 +134,7 @@ export default {
       return this.roles.includes('create-identifier') && userService.hasReadAccess(this.access)
     },
     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/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..5381fee565a0953fec4b7b523b425a54f1e99229 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'
@@ -197,11 +156,7 @@ export const useUserService = (): any => {
     update,
     create,
     updatePassword,
-    obtainToken,
     refreshToken,
-    tokenToRoles,
-    tokenToUserId,
-    userInfoToUser,
     nameIdentifierToNameIdentifierScheme,
     userToFullName,
     hasReadAccess,
diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue
index 0ad4cb818d353d283c15d0cc7c6240fec513a54b..e65a25690654b2bd87ad618c795fb2f0658b92b2 100644
--- a/dbrepo-ui/layouts/default.vue
+++ b/dbrepo-ui/layouts/default.vue
@@ -96,16 +96,16 @@
           @click:append-inner="retrieve" />
         <v-spacer />
         <v-btn
-          v-if="!user"
+          v-if="!loggedIn"
           class="mr-2"
           color="secondary"
           variant="flat"
           :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-login' : null"
-          to="/login">
+          @click="login()">
           {{ $t('navigation.login') }}
         </v-btn>
         <v-btn
-          v-if="!user"
+          v-if="!loggedIn"
           color="primary"
           variant="flat"
           :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-account-plus' : null"
@@ -113,12 +113,12 @@
           {{ $t('navigation.signup') }}
         </v-btn>
         <v-btn
-          v-if="user"
+          v-if="loggedIn"
           to="/user"
           variant="plain"
-          :text="user.username" />
+          :text="userInfo.preferred_username" />
         <v-menu
-          v-if="user"
+          v-if="loggedIn"
           location="bottom">
           <template v-slot:activator="{ props }">
             <v-btn
@@ -140,7 +140,7 @@
             </v-list-item>
             <v-list-item
               v-if="user"
-              @click="logout">
+              @click="logout()">
               {{ $t('navigation.logout') }}
             </v-list-item>
           </v-list>
@@ -163,6 +163,9 @@
 <script setup>
 import { ref } from 'vue'
 
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
 const runtimeConfig = useRuntimeConfig()
 const config = ref(runtimeConfig)
 useServerHead({
@@ -175,10 +178,10 @@ 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'
 
+
 export default {
   components: {
     JumboBox
@@ -197,26 +200,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
     },
@@ -244,9 +234,6 @@ export default {
       }
       return 'database'
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     version () {
       return this.$config.public.version
     },
@@ -295,6 +282,9 @@ export default {
     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'
@@ -319,8 +309,8 @@ export default {
           .catch((error) => {
             this.databaseError = error
           })
-        if (this.user) {
-          this.userStore.setRouteAccess(newObj.database_id)
+        if (this.userInfo) {
+          this.cacheStore.setRouteAccess(newObj.database_id, this.userInfo.uid)
         }
         /* load table */
         if (newObj.table_id) {
@@ -357,27 +347,14 @@ export default {
     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()
-      }
       if (!this.locale) {
-        this.userStore.setLocale('en')
+        this.cacheStore.setLocale('en')
+        return
       }
       this.$i18n.locale = this.locale
     },
@@ -398,7 +375,7 @@ export default {
       }
     },
     setLocale (code) {
-      this.userStore.setLocale(code)
+      this.cacheStore.setLocale(code)
       this.$i18n.locale = this.locale
     }
   }
diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts
index 4b1833d8162e7e1494f4164fa90bb76e107f7635..1804b3a3fd322ffe6cc5ae82e8c9ae6bace1f0a8 100644
--- a/dbrepo-ui/nuxt.config.ts
+++ b/dbrepo-ui/nuxt.config.ts
@@ -107,11 +107,32 @@ export default defineNuxtConfig({
     port: 3001
   },
 
+  oidc: {
+    providers: {
+      keycloak: {
+        audience: 'account',
+        baseUrl: 'http://localhost:8080/realms/dbrepo',
+        clientId: 'dbrepo-client',
+        clientSecret: '', // inject on runtime
+        scope: ['openid', 'roles'],
+        optionalClaims: ['realm_access'],
+        redirectUri: 'http://localhost/auth/keycloak/callback',
+        userNameClaim: 'preferred_username',
+        exposeAccessToken: true,
+        logoutRedirectUri: 'http://localhost',
+      },
+    },
+    middleware: {
+      globalMiddlewareEnabled: 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 +181,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..ec3ae1e6a44710998f0642760cf1e506b1d546d3 100644
--- a/dbrepo-ui/package.json
+++ b/dbrepo-ui/package.json
@@ -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..ec2149372e509c064d45e0ee684a60824bf17520 100644
--- a/dbrepo-ui/pages/container/index.vue
+++ b/dbrepo-ui/pages/container/index.vue
@@ -25,19 +25,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..33d63b29a938d7cb9fa5015605846a9a42d85a17 100644
--- a/dbrepo-ui/pages/database/[database_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/info.vue
@@ -163,13 +163,17 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+</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 +201,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -223,15 +226,9 @@ export default {
       }
       return this.database.identifier.publisher
     },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     identifiers () {
       if (!this.database) {
         return []
@@ -257,7 +254,7 @@ export default {
       return this.filteredIdentifiers[0]
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     pid () {
       return this.$route.query.pid
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..2c2e5ef120a044b4d2f551e0508fd842678aa7a9 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
@@ -8,10 +8,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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,17 +44,10 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
index df675d262e8e116b0c4252d74fe6878681388acb..a3581c0c828aec8b076151d306bd5a15ab69e16a 100644
--- a/dbrepo-ui/pages/database/[database_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
@@ -8,10 +8,16 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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,17 +41,10 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -56,10 +55,10 @@ export default {
       return false
     },
     isOwner () {
-      if (!this.database || !this.user) {
+      if (!this.database || !this.userInfo) {
         return false
       }
-      return this.database.owner.username === this.user.username
+      return this.database.owner.id === this.userInfo.uid
     },
     canCreateIdentifier () {
       if (!this.roles || this.hasIdentifier) {
diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue
index d0fb517daebc37d65c3d18f1faed9f631a0ecff0..5b0aa2a4537a69cd943cf6528b12ee14f94e44b3 100644
--- a/dbrepo-ui/pages/database/[database_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/settings.vue
@@ -244,10 +244,16 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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 +329,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -335,16 +340,7 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
-    },
-    token () {
-      return this.userStore.getToken
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
+      return this.cacheStore.getAccess
     },
     uploadProgress () {
       return this.cacheStore.getUploadProgress
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..a9956278d100eae3c66f50ad0ca2b8e461a4588d 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
@@ -92,7 +92,6 @@ 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 +133,6 @@ export default {
       downloadLoading: false,
       error: false,
       promises: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -146,14 +144,11 @@ export default {
       return this.cacheStore.getDatabase
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     subset () {
       return this.cacheStore.getSubset
     },
-    user () {
-      return this.userStore.getUser
-    },
     identifiers () {
       if (!this.database || !this.database.subsets || this.database.subsets.length === 0) {
         return []
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..0e1dac8c7e7fef9dfa3d4b50bad535af3f4ddfbc 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
@@ -8,10 +8,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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,17 +52,10 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
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..cc0dbf495865c2276d15411b2d8f05bd69c5cefb 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
@@ -9,10 +9,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <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,19 +52,15 @@ 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
     },
     canPersistQuery () {
       if (this.loadingQuery || !this.query) {
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
index 0fb591f9f8307018da13539491089c68c2a9ba16..2ea1c5022a9932dab4a655f0ebd19a9d522e9ba1 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
@@ -6,8 +6,13 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
-import { useUserStore } from '@/stores/user.js'
 import Builder from '@/components/subset/Builder.vue'
 import {useCacheStore} from '@/stores/cache.js'
 
@@ -36,22 +41,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
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!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..ca120e89f737ffc602c80378cc2bd27bb15fed89 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
@@ -81,6 +81,7 @@
         @close="pickVersion" />
     </v-dialog>
     <v-dialog
+      v-if="loggedIn"
       v-model="addTupleDialog"
       persistent
       max-width="640">
@@ -91,6 +92,7 @@
         @close="close" />
     </v-dialog>
     <v-dialog
+      v-if="loggedIn"
       v-model="editTupleDialog"
       persistent
       max-width="640">
@@ -104,12 +106,18 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</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'
@@ -179,25 +187,18 @@ 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
-    },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
@@ -230,10 +231,10 @@ export default {
       return this.version.substring(0, 10) + 'T' + this.version.substring(11, 19) + 'Z'
     },
     canModify () {
-      if (!this.user || !this.access || !this.table) {
+      if (!this.userInfo || !this.access || !this.table) {
         return false
       }
-      if (this.access.type === 'write_own' && this.table.owner.id === this.user.id) {
+      if (this.access.type === 'write_own' && this.table.owner.id === this.userInfo.uid) {
         return true
       }
       return this.access.type === 'write_all'
@@ -264,28 +265,28 @@ export default {
         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.userInfo) && 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.userInfo) && 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.userInfo) && 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.userInfo) && 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..46eb7106fd8449b93e4403abc2b2866280e3403b 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
@@ -28,9 +28,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import TableImport from '@/components/table/TableImport.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -69,17 +75,10 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     table () {
       return this.cacheStore.getTable
     },
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..ca295a558743451b37ea415691861c864b0bbdbc 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
@@ -118,12 +118,18 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</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 +171,6 @@ export default {
       loading: false,
       exchange: null,
       queue: null,
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -173,18 +178,12 @@ export default {
     pid () {
       return this.$route.query.pid
     },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
     table () {
       return this.cacheStore.getTable
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     canRead () {
       if (this.database && this.database.is_public) {
         return true
@@ -204,19 +203,19 @@ export default {
       if (this.table.is_schema_public || this.table.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.userInfo) {
         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.userInfo.uid || this.database.owner.id === this.userInfo.uid
     },
     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'
+      return (this.access.type === 'write_own' && this.table.owned_by === this.userInfo.uid) || this.access.type === 'write_all'
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasDescription () {
       return this.table && this.table.description
@@ -237,10 +236,10 @@ export default {
       if (!this.identifiers) {
         return []
       }
-      if (!this.user) {
+      if (!this.userInfo) {
         return this.identifiers.filter(i => i.status === 'published')
       }
-      return this.identifiers.filter(i => i.status === 'published' || i.owned_by === this.user.id)
+      return this.identifiers.filter(i => i.status === 'published' || i.owned_by === this.userInfo.uid)
     },
     identifier () {
       if (this.pid) {
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..0e82a2210beba8d7bce5865bf12234e2c43a279a 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
@@ -6,9 +6,14 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -45,17 +50,10 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
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..ef608876be1e974c216b80cbba5903d9d32c716e 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
@@ -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,19 +47,15 @@ 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
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..4cbb8d37d1abfd1c88b5daebd579e403a5545705 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,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</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 +174,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 +185,7 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
@@ -191,9 +193,6 @@ 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
@@ -204,16 +203,16 @@ export default {
       if (this.table.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.userInfo) {
         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.userInfo.uid || this.database.owner.id === this.userInfo.uid
     },
     primaryKeysColumns () {
       return this.table.constraints.primary_key.map(pk => pk.column.internal_name).join(', ')
     },
     canAssignSemanticInformation () {
-      if (!this.user) {
+      if (!this.userInfo) {
         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.userInfo.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..ddf319328ca039f0fbe1230117b6dc89eff31646 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,7 @@
     v-if="canUpdateTable">
     <TableToolbar />
     <v-window
-      v-if="user"
+      v-if="loggedIn"
       v-model="tab">
       <v-window-item>
         <v-form
@@ -114,9 +114,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 import { max } from '@/utils'
 
@@ -175,14 +181,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,7 +192,7 @@ export default {
       return this.cacheStore.getTable
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
@@ -198,9 +200,6 @@ export default {
       }
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     isChange () {
       if (!this.table) {
         return false
@@ -211,26 +210,26 @@ export default {
       return this.table.is_schema_public !== this.modify.is_schema_public
     },
     canUpdateTable () {
-      if (!this.roles || !this.user || !this.table) {
+      if (!this.roles || !this.userInfo || !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.userInfo.uid
     },
     canModifyVisibility () {
-      if (!this.roles || !this.user || !this.table) {
+      if (!this.roles || !this.userInfo || !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.userInfo.uid
     },
     canDropTable () {
-      if (!this.roles || !this.table || !this.user) {
+      if (!this.roles || !this.table || !this.userInfo) {
         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.userInfo) && 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..78bd1367513474e92efdc02efdeb93a537819729 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
@@ -219,10 +219,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</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 +309,6 @@ export default {
       loading: false,
       url: null,
       columns: [],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -316,12 +320,6 @@ 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
     },
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..cf8de848de793631ee2064bd84ad41010a0a0f17 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
@@ -185,10 +185,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</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 {
@@ -247,7 +252,6 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
@@ -259,12 +263,6 @@ 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
     },
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..0b0caa3c4fc82b414b91c48bed401ebc239d0351 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
@@ -34,10 +34,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+</script>
 <script>
 import TimeDrift from '@/components/TimeDrift.vue'
 import QueryResults from '@/components/subset/Results.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -70,14 +75,10 @@ export default {
           disabled: true
         }
       ],
-      cacheStore: useCacheStore(),
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -85,7 +86,7 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
@@ -100,10 +101,10 @@ export default {
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.userInfo) {
         return false
       }
-      return this.view.owner.id === this.user.id || this.hasReadAccess
+      return this.view.owner.id === this.userInfo.uid || this.hasReadAccess
     },
   },
   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..0ed006c4bef542f4bf5f4f51eeb2fd760f004acc 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
@@ -59,13 +59,18 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+</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,22 +108,15 @@ 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
@@ -139,10 +137,10 @@ export default {
       if (!this.identifiers) {
         return []
       }
-      if (!this.user) {
+      if (!this.userInfo) {
         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.userInfo.uid)
     },
     identifier () {
       if (this.pid) {
@@ -179,10 +177,10 @@ export default {
       if (this.view.is_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.userInfo) {
         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.userInfo.uid || this.database.owner.id === this.userInfo.uid
     }
   },
   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..f528c86675b9d48f1d7d0a2a68cfd614b946442b 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
@@ -8,9 +8,14 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -47,17 +52,10 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
-    user () {
-      return this.userStore.getUser
-    },
     database () {
       return this.cacheStore.getDatabase
     },
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..c5082c3be9bd10250df6be5957c620d813f73326 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
@@ -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,14 +44,10 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore(),
       cacheStore: useCacheStore()
     }
   },
   computed: {
-    roles () {
-      return this.userStore.getRoles
-    },
     database () {
       return this.cacheStore.getDatabase
     },
@@ -63,7 +58,7 @@ export default {
       return this.database.views.filter(v => v.id === Number(this.$route.params.view_id))[0]
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     canPersistView () {
       if (!this.view) {
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..5bd1ff5f9cf6019d6e36e4dd316ee9b43848a8d1 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
@@ -51,9 +51,14 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -95,14 +100,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,7 +111,7 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
@@ -125,13 +126,10 @@ export default {
       if (this.view.is_schema_public) {
         return true
       }
-      if (!this.user) {
+      if (!this.userInfo) {
         return false
       }
-      return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id
-    },
-    roles () {
-      return this.userStore.getRoles
+      return this.hasReadAccess || this.view.owner.id === this.userInfo.uid || this.database.owner.id === this.userInfo.uid
     },
     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..575e5b5f27d484a248ef7df71f9ff1c013baefc5 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
@@ -90,9 +90,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import ViewToolbar from '@/components/view/ViewToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 import { useCacheStore } from '@/stores/cache.js'
 
 export default {
@@ -148,14 +154,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,7 +165,7 @@ export default {
       return this.cacheStore.getView
     },
     access () {
-      return this.userStore.getAccess
+      return this.cacheStore.getAccess
     },
     hasReadAccess () {
       if (!this.access) {
@@ -171,9 +173,6 @@ export default {
       }
       return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own'
     },
-    roles () {
-      return this.userStore.getRoles
-    },
     isChange () {
       if (!this.view) {
         return false
@@ -184,22 +183,22 @@ 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.userInfo || !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.userInfo.uid
     },
     canDeleteView () {
-      if (!this.roles || !this.user || !this.view) {
+      if (!this.roles || !this.userInfo || !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.userInfo.uid
     },
     canViewSettings () {
-      if (!this.user || !this.view) {
+      if (!this.userInfo || !this.view) {
         return false
       }
-      return this.view.owner.id === this.user.id
+      return this.view.owner.id === this.userInfo.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..b9d4a684d764de219014e7f840c422b98a2d4c75 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/create.vue
@@ -6,9 +6,14 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import Builder from '@/components/subset/Builder.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -34,17 +39,10 @@ export default {
           to: `/database/${this.$route.params.database_id}/view/create`,
           disabled: true
         }
-      ],
-      userStore: useUserStore()
+      ]
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     canCreateView () {
       if (!this.roles) {
         return false
diff --git a/dbrepo-ui/pages/index.vue b/dbrepo-ui/pages/index.vue
index 1c30c25e5c7e9edfd52861ca568c492ce39f13a7..16cbbb283fd3a86e14dfb4865c4d61477ad2cf8e 100644
--- a/dbrepo-ui/pages/index.vue
+++ b/dbrepo-ui/pages/index.vue
@@ -27,10 +27,12 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn, user, login, logout } = useOidcAuth()
+</script>
 <script>
 import DatabaseList from '@/components/database/DatabaseList.vue'
 import DatabaseCreate from '@/components/database/DatabaseCreate.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -41,13 +43,21 @@ export default {
     return {
       loading: true,
       dialog: null,
-      databases: [],
-      userStore: useUserStore()
+      databases: []
     }
   },
   computed: {
+    userInfo () {
+      if (!this.user) {
+        return null
+      }
+      return this.user.userInfo
+    },
     roles () {
-      return this.userStore.getRoles
+      if (!this.user) {
+        return []
+      }
+      return []
     },
     canCreateDatabase () {
       if (!this.roles) {
@@ -57,17 +67,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..ca80b1efda6c185a0e39323cb66c13d0a131e97b 100644
--- a/dbrepo-ui/pages/search.vue
+++ b/dbrepo-ui/pages/search.vue
@@ -63,9 +63,14 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import AdvancedSearch from '@/components/search/AdvancedSearch.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -75,14 +80,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
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
index 54c00602256c7815d8aff0b255214e66836bc727..19f781572a73f9be766bcb3a91c8c4fd2bb6c9e5 100644
--- a/dbrepo-ui/pages/signup.vue
+++ b/dbrepo-ui/pages/signup.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="!loggedIn">
     <v-toolbar
       :title="$t('pages.signup.name')"
       flat />
@@ -91,6 +92,9 @@
   </div>
 </template>
 
+<script setup>
+const { loggedIn, user, login, logout } = useOidcAuth()
+</script>
 <script>
 export default {
   data () {
diff --git a/dbrepo-ui/pages/user/authentication.vue b/dbrepo-ui/pages/user/authentication.vue
index 3a43421a709560b3e841760620321f0c640275f9..03c40e5d82f9ac2a787a663eab1e6b7fb2f89699 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,15 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import UserToolbar from '@/components/user/UserToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
 
 export default {
   components: {
@@ -87,14 +93,10 @@ export default {
       ],
       email: null,
       password: null,
-      password2: null,
-      userStore: useUserStore()
+      password2: null
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
     inputVariant () {
       const runtimeConfig = useRuntimeConfig()
       return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : runtimeConfig.public.variant.input.normal
@@ -104,15 +106,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.userInfo.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..1d76677059d6dbc26ad41ac48bfaf88d3ef6acb2 100644
--- a/dbrepo-ui/pages/user/index.vue
+++ b/dbrepo-ui/pages/user/index.vue
@@ -2,25 +2,13 @@
   <div />
 </template>
 
+<script setup>
+const { loggedIn, user, login, logout } = useOidcAuth()
+</script>
 <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) {
+    if (!this.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..58e265b59ffe78ce7627c572df60e91b67e24df3 100644
--- a/dbrepo-ui/pages/user/info.vue
+++ b/dbrepo-ui/pages/user/info.vue
@@ -1,7 +1,8 @@
 <template>
   <div>
     <UserToolbar />
-    <v-window v-model="tab">
+    <v-window
+      v-model="tab">
       <v-window-item>
         <v-form v-model="valid1" @submit.prevent="submit">
           <v-card
@@ -122,9 +123,16 @@
   </div>
 </template>
 
+<script setup>
+import { ref } from 'vue'
+
+const { loggedIn, user, login, logout } = useOidcAuth()
+const userInfo = ref(loggedIn ? user.value?.userInfo : null)
+const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : [])
+</script>
 <script>
 import UserToolbar from '@/components/user/UserToolbar.vue'
-import { useUserStore } from '@/stores/user.js'
+import { useCacheStore } from '@/stores/cache.js'
 
 export default {
   components: {
@@ -169,18 +177,12 @@ export default {
           disabled: true
         }
       ],
-      userStore: useUserStore()
+      cacheStore: useCacheStore()
     }
   },
   computed: {
-    user () {
-      return this.userStore.getUser
-    },
-    roles () {
-      return this.userStore.getRoles
-    },
     locale () {
-      return this.userStore.getLocale
+      return this.cacheStore.getLocale
     },
     canModifyTheme () {
       return this.roles.includes('modify-user-theme')
@@ -214,14 +216,13 @@ export default {
         language: this.model.language,
       }
       const userService = useUserService()
-      userService.update(this.user.id, payload)
+      userService.update(this.userInfo.id, 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) {
@@ -251,14 +252,14 @@ export default {
         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.userInfo.id,
+        username: this.userInfo.username,
+        firstname: this.userInfo.given_name,
+        lastname: this.userInfo.family_name,
+        orcid: this.userInfo.attributes.orcid,
+        affiliation: this.userInfo.attributes.affiliation,
+        theme: this.userInfo.attributes.theme,
+        language: this.userInfo.attributes.language
       }
     },
     retrieve () {
diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js
index 41059ba7270d93717998ac5b245e37d6ed239ee3..4582dce19945e18b962b1ee5a5f4da7d368ed80b 100644
--- a/dbrepo-ui/stores/cache.js
+++ b/dbrepo-ui/stores/cache.js
@@ -7,7 +7,9 @@ export const useCacheStore = defineStore('cache', {
       database: null,
       table: null,
       view: null,
+      access: null,
       subset: null,
+      locale: null,
       ontologies: [],
       messages: [],
       uploadProgress: null
@@ -17,7 +19,9 @@ 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,
     getOntologies: (state) => state.ontologies,
     getMessages: (state) => state.messages,
     getUploadProgress: (state) => state.uploadProgress,
@@ -32,9 +36,15 @@ 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
+    },
     setOntologies(ontologies) {
       this.ontologies = ontologies
     },
@@ -117,6 +127,16 @@ export const useCacheStore = defineStore('cache', {
       tableService.findOne(databaseId, tableId)
         .then(table => this.table = table)
     },
+    setRouteAccess(databaseId, userId) {
+      if (!databaseId || !userId) {
+        this.access = null
+        console.error('Cannot set route access: missing database id', databaseId, 'or user id', userId)
+        return
+      }
+      const accessService = useAccessService()
+      accessService.findOne(databaseId, userId)
+        .then(access => this.access = access)
+    },
     setRouteView(databaseId, viewId) {
       if (!databaseId || !viewId) {
         this.view = null
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/docker-compose.yml b/docker-compose.yml
index ad1dacb6b7b19a8fb4ee3303968cd684bef75967..efcc9a76ccf71be7b78c49cd842d66e7f868deca 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -329,8 +329,13 @@ services:
       network: host
     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_BASE_URL: "${BASE_URL:-http://localhost:8080}/realms/dbrepo"
+      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
@@ -341,6 +346,8 @@ services:
       interval: 10s
       timeout: 5s
       retries: 12
+    extra_hosts:
+      - "localhost:host-gateway"
     logging:
       driver: json-file