From 0123f1c3f9dafd48d1cd5d0eb85a8eafe7879f83 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Fri, 1 Dec 2023 15:55:22 +0100
Subject: [PATCH] Finished #396

- Fixed the tests
- Updated frontend state
- Fixed the access token refresh
---
 .../dbrepo-realm.json                         | 56 +++++++++----------
 .../java/at/tuwien/mapper/TableMapper.java    | 26 ++-------
 .../service/ViewServiceIntegrationTest.java   |  5 +-
 .../tuwien/service/impl/TableServiceImpl.java |  2 +-
 .../main/java/at/tuwien/test/BaseTest.java    |  4 +-
 dbrepo-ui/api/authentication.service.js       | 12 +---
 dbrepo-ui/layouts/default.vue                 | 17 ------
 .../_database_id/table/_table_id/data.vue     |  2 +-
 dbrepo-ui/plugins/axios.js                    | 20 ++++---
 dbrepo-ui/plugins/vuex-persist.js             | 17 +++++-
 dbrepo-ui/store/index.js                      |  3 +-
 11 files changed, 72 insertions(+), 92 deletions(-)

diff --git a/dbrepo-authentication-service/dbrepo-realm.json b/dbrepo-authentication-service/dbrepo-realm.json
index 235c16a720..dbd6c6cc5b 100644
--- a/dbrepo-authentication-service/dbrepo-realm.json
+++ b/dbrepo-authentication-service/dbrepo-realm.json
@@ -5,10 +5,10 @@
   "defaultSignatureAlgorithm" : "RS256",
   "revokeRefreshToken" : false,
   "refreshTokenMaxReuse" : 1,
-  "accessTokenLifespan" : 720,
+  "accessTokenLifespan" : 86400,
   "accessTokenLifespanForImplicitFlow" : 900,
-  "ssoSessionIdleTimeout" : 1296000,
-  "ssoSessionMaxLifespan" : 1296000,
+  "ssoSessionIdleTimeout" : 1800,
+  "ssoSessionMaxLifespan" : 36000,
   "ssoSessionIdleTimeoutRememberMe" : 0,
   "ssoSessionMaxLifespanRememberMe" : 0,
   "offlineSessionIdleTimeout" : 2592000,
@@ -2035,7 +2035,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper" ]
+        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -2061,11 +2061,11 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper" ]
       }
     } ],
     "org.keycloak.userprofile.UserProfileProvider" : [ {
-      "id" : "5da93330-911b-44c9-b971-5176ed5ce1f9",
+      "id" : "7970b87f-f28b-4085-8612-43281968f118",
       "providerId" : "declarative-user-profile",
       "subComponents" : { },
       "config" : { }
@@ -2119,7 +2119,7 @@
   "internationalizationEnabled" : false,
   "supportedLocales" : [ ],
   "authenticationFlows" : [ {
-    "id" : "88c24c27-94a1-4473-b545-bda821e22216",
+    "id" : "7b9f9c3b-0636-406b-8ac3-c7259ef423d3",
     "alias" : "Account verification options",
     "description" : "Method with which to verity the existing account",
     "providerId" : "basic-flow",
@@ -2141,7 +2141,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "796e78cb-67d5-4411-a163-bcc93afde7d3",
+    "id" : "70be7410-8823-4c0f-aa70-39d9d0e1c7f2",
     "alias" : "Authentication Options",
     "description" : "Authentication options.",
     "providerId" : "basic-flow",
@@ -2170,7 +2170,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "42e0b37c-1cd9-4472-8a3c-aff3f5903283",
+    "id" : "c3bfd9c1-1e61-4789-9797-7e28867ac15b",
     "alias" : "Browser - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2192,7 +2192,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "6493953f-c9d1-44e6-8adb-0355eaecb65b",
+    "id" : "ba6106ab-6fca-43b3-a170-c1db8352fc69",
     "alias" : "Direct Grant - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2214,7 +2214,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "c247859c-1171-4ac1-b93f-e4f17a758226",
+    "id" : "bd04da6b-71b0-42d0-a279-4402b7cf35cf",
     "alias" : "First broker login - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2236,7 +2236,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "5a61e41a-80fb-4848-a457-90cc1c93b625",
+    "id" : "2016d479-271f-4dfd-88c3-50635d1d27ea",
     "alias" : "Handle Existing Account",
     "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
     "providerId" : "basic-flow",
@@ -2258,7 +2258,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "bf35008a-4f40-44c0-bc26-994cf2b8fc5f",
+    "id" : "3294bcec-0829-405e-bc34-897eb5ecbf62",
     "alias" : "Reset - Conditional OTP",
     "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
     "providerId" : "basic-flow",
@@ -2280,7 +2280,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "a001a5ff-780d-4d61-a60d-f0cce53b2726",
+    "id" : "cdc002be-a391-4853-8c40-8eef726dcfb6",
     "alias" : "User creation or linking",
     "description" : "Flow for the existing/non-existing user alternatives",
     "providerId" : "basic-flow",
@@ -2303,7 +2303,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "49f8350a-151f-409d-8a8d-642cfffa2a96",
+    "id" : "11e9d0a5-743f-44fe-ab9f-59f3e730e20a",
     "alias" : "Verify Existing Account by Re-authentication",
     "description" : "Reauthentication of existing account",
     "providerId" : "basic-flow",
@@ -2325,7 +2325,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ae555215-51f3-426d-ada9-36963bff44ef",
+    "id" : "c5ea7e5c-c07d-48c5-ba99-4e84ed167bee",
     "alias" : "browser",
     "description" : "browser based authentication",
     "providerId" : "basic-flow",
@@ -2361,7 +2361,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "74aae05a-433a-468e-959e-a8e23fcc89c0",
+    "id" : "e18342ad-98d9-4411-bf59-30e07cf65f98",
     "alias" : "clients",
     "description" : "Base authentication for clients",
     "providerId" : "client-flow",
@@ -2397,7 +2397,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "f2aaa4a5-ee8b-42c4-b633-2e7d63bb1fc2",
+    "id" : "ca97318e-8587-43b4-919b-5c65e2a074f3",
     "alias" : "direct grant",
     "description" : "OpenID Connect Resource Owner Grant",
     "providerId" : "basic-flow",
@@ -2426,7 +2426,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "677394eb-81d5-401f-a288-43935b39989a",
+    "id" : "7f523ba5-6d6b-4a65-9ba0-107b5c3afe7a",
     "alias" : "docker auth",
     "description" : "Used by Docker clients to authenticate against the IDP",
     "providerId" : "basic-flow",
@@ -2441,7 +2441,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "8d2809c9-9b3e-4c96-9768-5c89e752676a",
+    "id" : "c72a0c74-0dc4-45dc-8b62-a77bc42d805c",
     "alias" : "first broker login",
     "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
     "providerId" : "basic-flow",
@@ -2464,7 +2464,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "7024c35c-81a5-4f73-ad1e-366f4a488175",
+    "id" : "5939da5a-b299-49b7-8c07-c45e13d995db",
     "alias" : "forms",
     "description" : "Username, password, otp and other auth forms.",
     "providerId" : "basic-flow",
@@ -2486,7 +2486,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "a6764496-699f-42d8-aa04-1e996c5f014e",
+    "id" : "6a0341db-eec8-4962-bb04-4b8a43dced2a",
     "alias" : "http challenge",
     "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
     "providerId" : "basic-flow",
@@ -2508,7 +2508,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "fe150e10-946a-441f-aef5-417e171ca49f",
+    "id" : "525006c3-c676-4bfb-83cf-79faeafe0183",
     "alias" : "registration",
     "description" : "registration flow",
     "providerId" : "basic-flow",
@@ -2524,7 +2524,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "5de2ec52-872f-462c-b994-47f59a31b5ab",
+    "id" : "65e9d76b-d180-47e6-ad1b-dddea414668f",
     "alias" : "registration form",
     "description" : "registration form",
     "providerId" : "form-flow",
@@ -2560,7 +2560,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "5833fbd7-31d4-4cf3-95db-6e6beb40a2a5",
+    "id" : "feb110ed-e018-43ba-8989-0b17a3a20de3",
     "alias" : "reset credentials",
     "description" : "Reset credentials for a user if they forgot their password or something",
     "providerId" : "basic-flow",
@@ -2596,7 +2596,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "64902f62-0b27-4174-8d66-88910be9fcfd",
+    "id" : "15efa29f-2140-4e3b-803e-64d79906c18b",
     "alias" : "saml ecp",
     "description" : "SAML ECP Profile Authentication Flow",
     "providerId" : "basic-flow",
@@ -2612,13 +2612,13 @@
     } ]
   } ],
   "authenticatorConfig" : [ {
-    "id" : "e1ad59c1-8db5-4381-b7b9-cc97d5653236",
+    "id" : "2c135401-6244-41b0-8c49-648f38b5e1bd",
     "alias" : "create unique user config",
     "config" : {
       "require.password.update.after.registration" : "false"
     }
   }, {
-    "id" : "81d8abc7-c14e-4b41-9432-8ea38cd8a0e3",
+    "id" : "39d00721-0854-4ff7-9f5c-7f6fa71ae37a",
     "alias" : "review profile config",
     "config" : {
       "update.profile.on.first.login" : "missing"
diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java
index c42c8f1625..d5fe384b34 100644
--- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java
+++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java
@@ -479,31 +479,17 @@ public interface TableMapper {
     }
 
     default PreparedStatement tableToCreateHistoryViewRawQuery(Connection connection, Table data) throws QueryMalformedException {
-        final StringBuilder keys = new StringBuilder();
-        final StringBuilder statement = new StringBuilder("CREATE VIEW `hs_")
+        final StringBuilder view = new StringBuilder("CREATE VIEW `hs_")
                 .append(data.getInternalName())
-                .append("` AS SELECT * FROM (SELECT ");
-        final int[] idx = new int[]{0};
-        data.getColumns()
-                .stream()
-                .filter(c -> Objects.nonNull(c.getIsPrimaryKey()))
-                .filter(TableColumn::getIsPrimaryKey)
-                .forEach(c -> keys.append(idx[0]++ > 0 ? "," : "")
-                        .append("`")
-                        .append(c.getInternalName())
-                        .append("`"));
-        statement.append(keys)
-                .append(", ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at, COUNT(*) as total FROM `")
+                .append("` AS SELECT * FROM (SELECT ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at, COUNT(*) as total FROM `")
                 .append(data.getInternalName())
-                .append("` FOR SYSTEM_TIME ALL GROUP BY ")
-                .append(keys)
-                .append(", inserted_at, deleted_at ORDER BY deleted_at DESC LIMIT 50) AS v ORDER BY v.inserted_at, v.deleted_at ASC");
+                .append("` FOR SYSTEM_TIME ALL GROUP BY inserted_at, deleted_at ORDER BY deleted_at DESC LIMIT 50) AS v ORDER BY v.inserted_at, v.deleted_at ASC");
         try {
-            final PreparedStatement pstmt = connection.prepareStatement(statement.toString());
-            log.trace("prepared create sequence statement {}", statement);
+            final PreparedStatement pstmt = connection.prepareStatement(view.toString());
+            log.trace("prepared create view statement {}", view);
             return pstmt;
         } catch (SQLException e) {
-            log.error("failed to prepare statement {}, reason: {}", statement, e.getMessage());
+            log.error("Failed to prepare statement: {}", e.getMessage());
             throw new QueryMalformedException("Failed to prepare statement", e);
         }
     }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
index caa1271611..68525e6729 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java
@@ -135,12 +135,11 @@ public class ViewServiceIntegrationTest extends BaseUnitTest {
         assertEquals("7.4", resultSet.get(1).get("mintemp"));
         assertEquals("0", resultSet.get(1).get("rainfall"));
         assertEquals("Albury", resultSet.get(1).get("location"));
-        assertEquals("2008-12-01", resultSet.get(1).get("date"));
+        assertEquals("2008-12-02", resultSet.get(1).get("date"));
         assertEquals("12.9", resultSet.get(2).get("mintemp"));
         assertEquals("0", resultSet.get(2).get("rainfall"));
         assertEquals("Albury", resultSet.get(2).get("location"));
-        assertEquals("2008-12-01", resultSet.get(2).get("date"));
-        /* more result checks omitted */
+        assertEquals("2008-12-03", resultSet.get(2).get("date"));
     }
 
     @Test
diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
index ae0a2643a2..16bfa35731 100644
--- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
+++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java
@@ -180,7 +180,7 @@ public class TableServiceImpl extends HibernateConnector implements TableService
             final Connection connection = dataSource.getConnection();
             generatedSequence = tableMapper.tableToCreateTableRawQuery(connection, createDto);
         } catch (Exception e) {
-            log.error("Failed to create table, reason: {}", e.getMessage());
+            log.error("Failed to create table: {}", e.getMessage());
             throw new TableMalformedException("Failed to create table", e);
         } finally {
             dataSource.close();
diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
index 50547102ad..91fc524226 100644
--- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
+++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
@@ -5291,8 +5291,8 @@ public abstract class BaseTest {
     public final static Long VIEW_3_CONTAINER_ID = CONTAINER_1_ID;
     public final static Long VIEW_3_DATABASE_ID = DATABASE_1_ID;
     public final static Boolean VIEW_3_PUBLIC = false;
-    public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`date` from `weather_aus` w join `junit2` m on m.`location` = w.`location`";
-    public final static String VIEW_3_QUERY_HASH = "297bbacf5bf142028d0f4a1e537db03fd91b0c3be9e66ea2abc13d2984d22824";
+    public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`date` from `weather_aus` w join `junit2` m on m.`location` = w.`location` and m.`date` = w.`date`";
+    public final static String VIEW_3_QUERY_HASH = "bbbaa56a5206b3dc3e6cf9301b0db9344eb6f19b100c7b88550ffb597a0bd255";
 
     public final static List<TableColumn> VIEW_3_COLUMNS = List.of(TableColumn.builder()
                     .id(COLUMN_1_4_ID)
diff --git a/dbrepo-ui/api/authentication.service.js b/dbrepo-ui/api/authentication.service.js
index 6f5d92d411..035a810620 100644
--- a/dbrepo-ui/api/authentication.service.js
+++ b/dbrepo-ui/api/authentication.service.js
@@ -91,19 +91,9 @@ class AuthenticationService {
         }).catch((error) => {
           console.error('Failed to authenticate', error)
           const { response } = error
-          const { status, data } = response
+          const { status } = response
           if (status === 401) {
             Vue.$toast.error('Invalid username-password combination.')
-          } else if (data && data.error && data.error === 'invalid_grant') {
-            store().commit('SET_TOKEN', null)
-            store().commit('SET_REFRESH_TOKEN', null)
-            store().commit('SET_ROLES', [])
-            store().commit('SET_USER', null)
-            this.$vuetify.theme.dark = false
-            Vue.$toast.warning('Authentication expired.')
-            this.$router.push('/login')
-          } else {
-            /* ignore */
           }
           reject(error)
         })
diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue
index 946b88a2de..66d6ee2385 100644
--- a/dbrepo-ui/layouts/default.vue
+++ b/dbrepo-ui/layouts/default.vue
@@ -149,7 +149,6 @@
 </template>
 
 <script>
-import AuthenticationService from '@/api/authentication.service'
 import DatabaseService from '@/api/database.service'
 import TableService from '@/api/table.service'
 
@@ -172,12 +171,6 @@ export default {
     availableLocales () {
       return this.$i18n.locales.filter(i => i.code !== this.$i18n.locale)
     },
-    token () {
-      return this.$store.state.token
-    },
-    refreshToken () {
-      return this.$store.state.refreshToken
-    },
     user () {
       return this.$store.state.user
     },
@@ -221,13 +214,6 @@ export default {
         this.$store.commit('SET_LOCALE', this.$i18n.locale)
       }
     },
-    $route: {
-      handler () {
-        if (this.refreshToken) {
-          AuthenticationService.authenticateToken(this.refreshToken)
-        }
-      }
-    },
     '$route.params.database_id': {
       handler (id, oldId) {
         if (id !== oldId) {
@@ -314,9 +300,6 @@ export default {
       if (!this.$route.params.database_id) {
         return
       }
-      if (!this.token) {
-        return
-      }
       this.loading = true
       DatabaseService.checkAccess(this.$route.params.database_id)
         .then((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 8a3df803ef..dde1904cff 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
@@ -8,7 +8,7 @@
       </v-toolbar-title>
       <v-spacer />
       <v-toolbar-title>
-        <v-btn class="mr-2" :loading="downloadLoading" @click.stop="download">
+        <v-btn :loading="downloadLoading" @click.stop="download">
           <v-icon left>mdi-download</v-icon> Download csv
         </v-btn>
         <v-btn @click="pick">
diff --git a/dbrepo-ui/plugins/axios.js b/dbrepo-ui/plugins/axios.js
index 0f67762dbf..7d475a2934 100644
--- a/dbrepo-ui/plugins/axios.js
+++ b/dbrepo-ui/plugins/axios.js
@@ -11,20 +11,26 @@ api.interceptors.request.use((config) => {
     return config
   }
   const { exp } = jwtDecode(token)
-  if (new Date(exp) <= new Date()) {
+  let accessTokenExpiryDate = new Date(exp * 1000)
+  if (accessTokenExpiryDate <= Date.now()) {
     /* token expired */
+    console.warn('access token has expired:', accessTokenExpiryDate)
     const refreshToken = store().state.refreshToken
-    const { exp2 } = jwtDecode(refreshToken)
-    if (new Date(exp2) <= new Date()) {
+    const refreshTokenExpiryDate = new Date(jwtDecode(refreshToken).exp * 1000)
+    if (refreshTokenExpiryDate <= Date.now()) {
       /* refresh token expired */
+      console.error('Refresh token expired')
       store().commit('SET_TOKEN', null)
       store().commit('SET_REFRESH_TOKEN', null)
-      console.warn('Refresh token expired')
+      return config
     }
     AuthenticationService.authenticateToken(refreshToken)
-      .then((authentication) => {
-        // console.debug('interceptor inject authorization header for url', config.url)
-        config.headers.Authorization = `Bearer ${authentication.access_token}`
+      .then((response) => {
+        accessTokenExpiryDate = new Date(jwtDecode(response.access_token).exp * 1000)
+        console.info('Successfully requested a new access token')
+        console.debug('new access token expires:', accessTokenExpiryDate)
+        console.debug('attach access token to intercepted request:', config.url)
+        config.headers.Authorization = `Bearer ${response.access_token}`
         return config
       })
       .finally(() => {
diff --git a/dbrepo-ui/plugins/vuex-persist.js b/dbrepo-ui/plugins/vuex-persist.js
index e74b481794..d9f892c78c 100644
--- a/dbrepo-ui/plugins/vuex-persist.js
+++ b/dbrepo-ui/plugins/vuex-persist.js
@@ -4,9 +4,24 @@ export default ({ store }) => {
   new VuexPersistence({
     storage: window.localStorage,
     reducer: state => ({
+      title: state.title,
+      icon: state.icon,
       token: state.token,
       refreshToken: state.refreshToken,
-      user: state.user
+      roles: state.roles,
+      user: state.user,
+      database: state.database,
+      table: state.table,
+      access: state.access,
+      locale: state.locale,
+      messages: state.messages,
+      ontologies: state.ontologies,
+      clientId: state.clientId,
+      clientSecret: state.clientSecret,
+      searchUsername: state.searchUsername,
+      searchPassword: state.searchPassword,
+      databaseCount: state.databaseCount,
+      doiUrl: state.doiUrl
     })
   }).plugin(store)
 }
diff --git a/dbrepo-ui/store/index.js b/dbrepo-ui/store/index.js
index b919a18df9..db1da92da9 100644
--- a/dbrepo-ui/store/index.js
+++ b/dbrepo-ui/store/index.js
@@ -10,6 +10,7 @@ Vue.use(Vuex)
 
 // https://github.com/hua1995116/webchat/blob/7c6544d3defd41cb7cf68306accea97800858bc3/client/src/store/index.js#L293
 const store = new Store({
+  // changes to the state information here *NEED* to be manually propagated to @/plugins/vuex-persist.js to be stored in the web-browser
   state: {
     title: null,
     icon: null,
@@ -158,7 +159,7 @@ const store = new Store({
     logout ({ state, commit }) {
       commit('SET_TOKEN', null)
       commit('SET_REFRESH_TOKEN', null)
-      commit('SET_ROLES', null)
+      commit('SET_ROLES', [])
       commit('SET_USER', null)
       commit('SET_DATABASE', null)
       commit('SET_ACCESS', null)
-- 
GitLab