diff --git a/fda-authentication-service/dbrepo-realm.json b/fda-authentication-service/dbrepo-realm.json
index c9ef98fe877d5521855642509e06805fab4d51ff..4fbca0146ae43df33caa79539ab5578be27a9b1a 100644
--- a/fda-authentication-service/dbrepo-realm.json
+++ b/fda-authentication-service/dbrepo-realm.json
@@ -870,7 +870,7 @@
   "otpPolicyLookAheadWindow" : 1,
   "otpPolicyPeriod" : 30,
   "otpPolicyCodeReusable" : false,
-  "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName", "totpAppFreeOTPName" ],
+  "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName" ],
   "webAuthnPolicyRpEntityName" : "keycloak",
   "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
   "webAuthnPolicyRpId" : "",
@@ -1072,6 +1072,20 @@
         "claim.name" : "aud",
         "access.tokenResponse.claim" : "false"
       }
+    }, {
+      "id" : "8ae79e43-b2b7-4bb9-a420-b498690dd8c3",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "false",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "false",
+        "access.token.claim" : "true",
+        "claim.name" : "user.firstname",
+        "jsonType.label" : "String"
+      }
     }, {
       "id" : "ef081a47-f023-4056-958c-4194d3878d8c",
       "name" : "username",
@@ -1086,9 +1100,23 @@
         "claim.name" : "client_id",
         "jsonType.label" : "String"
       }
+    }, {
+      "id" : "99e3b48b-86ff-4e5b-8652-fcd2738b0ad1",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "user.lastname",
+        "jsonType.label" : "String"
+      }
     } ],
-    "defaultClientScopes" : [ "profile", "roles", "attributes" ],
-    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
+    "defaultClientScopes" : [ "roles", "attributes" ],
+    "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ]
   }, {
     "id" : "25741f6b-4867-4138-8238-6345c6ba8702",
     "clientId" : "rabbitmq-client",
@@ -1815,7 +1843,7 @@
       "subType" : "anonymous",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper" ]
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper" ]
       }
     }, {
       "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1",
@@ -1841,7 +1869,7 @@
       "subType" : "authenticated",
       "subComponents" : { },
       "config" : {
-        "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ]
+        "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper" ]
       }
     } ],
     "org.keycloak.userprofile.UserProfileProvider" : [ {
@@ -1899,7 +1927,7 @@
   "internationalizationEnabled" : false,
   "supportedLocales" : [ ],
   "authenticationFlows" : [ {
-    "id" : "ffedba28-fef3-4e64-9b37-b3270858aa2a",
+    "id" : "9b2ffbe1-91b5-4815-b2c6-fdb8d5cf522e",
     "alias" : "Account verification options",
     "description" : "Method with which to verity the existing account",
     "providerId" : "basic-flow",
@@ -1921,7 +1949,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "34232f15-241f-4827-866b-2b03720a6885",
+    "id" : "d48e99bc-ce6f-4474-b1f1-2b87c578522d",
     "alias" : "Authentication Options",
     "description" : "Authentication options.",
     "providerId" : "basic-flow",
@@ -1950,7 +1978,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "871385ad-06e0-4bf8-b366-ffc256389f1c",
+    "id" : "61b23580-7996-49c4-8370-77bb1532c818",
     "alias" : "Browser - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -1972,7 +2000,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "a9fbd9c0-b524-40fb-bc90-23317dc3d611",
+    "id" : "598a4244-04b4-4a8d-9c99-1e1a41f1243b",
     "alias" : "Direct Grant - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -1994,7 +2022,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "cf030c87-aeab-453b-a50c-0a4454a5feb9",
+    "id" : "e7ee21a3-baf9-4259-b4c2-7ca8742d0521",
     "alias" : "First broker login - Conditional OTP",
     "description" : "Flow to determine if the OTP is required for the authentication",
     "providerId" : "basic-flow",
@@ -2016,7 +2044,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "4c156a62-d234-4af7-a609-3c7a0b58d7cf",
+    "id" : "718cf803-48b1-4a96-83b5-bad0ad92cdbb",
     "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",
@@ -2038,7 +2066,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "db5115da-e49d-4572-af14-a7cb12cf4424",
+    "id" : "2dae43c5-af72-4a1c-b315-798892e76982",
     "alias" : "Reset - Conditional OTP",
     "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
     "providerId" : "basic-flow",
@@ -2060,7 +2088,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "37d5aaaa-2514-4973-b5ae-89ac84bc8600",
+    "id" : "ca2e30ea-389c-403a-89de-950bbc488ad4",
     "alias" : "User creation or linking",
     "description" : "Flow for the existing/non-existing user alternatives",
     "providerId" : "basic-flow",
@@ -2083,7 +2111,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "725b445b-02ee-47ba-9ea2-2c3b8007a025",
+    "id" : "b11e2f51-ef59-4393-be70-064ed4e1321b",
     "alias" : "Verify Existing Account by Re-authentication",
     "description" : "Reauthentication of existing account",
     "providerId" : "basic-flow",
@@ -2105,7 +2133,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "5af07663-b611-464c-aefc-8da55b76d100",
+    "id" : "9a39c4b1-ba3c-403c-9620-b93e5a9da467",
     "alias" : "browser",
     "description" : "browser based authentication",
     "providerId" : "basic-flow",
@@ -2141,7 +2169,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "80ebd402-2fa1-42f3-b6b7-885c85ce1849",
+    "id" : "6c1d6c8e-e593-40d6-89c8-7b6044790717",
     "alias" : "clients",
     "description" : "Base authentication for clients",
     "providerId" : "client-flow",
@@ -2177,7 +2205,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "ab147f84-a2bf-4c35-83a4-fc662c9fb4f2",
+    "id" : "f650a4f6-e0b8-47da-8416-b805d7cb8535",
     "alias" : "direct grant",
     "description" : "OpenID Connect Resource Owner Grant",
     "providerId" : "basic-flow",
@@ -2206,7 +2234,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "87ecaa80-a8b6-47e5-af44-1915880a4ef7",
+    "id" : "363ceb8b-0902-4f97-9006-93d4e6fa3d9a",
     "alias" : "docker auth",
     "description" : "Used by Docker clients to authenticate against the IDP",
     "providerId" : "basic-flow",
@@ -2221,7 +2249,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "d79a5c9e-68a8-430e-97b0-197055caa873",
+    "id" : "41584462-4e61-45d3-bf42-cf1f19266804",
     "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",
@@ -2244,7 +2272,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "4df39289-f633-466c-9dfd-2ca6ff9445d0",
+    "id" : "e723d622-3bf1-4202-bf51-69de9548ec20",
     "alias" : "forms",
     "description" : "Username, password, otp and other auth forms.",
     "providerId" : "basic-flow",
@@ -2266,7 +2294,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "63948a28-ff5b-4a84-8f61-7d1a1e80773e",
+    "id" : "e6f26e36-d5cd-47e7-be78-7b9d21187a42",
     "alias" : "http challenge",
     "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
     "providerId" : "basic-flow",
@@ -2288,7 +2316,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "514330ab-3731-4245-86c0-9155d84fb714",
+    "id" : "e548e0c5-596a-467f-a23b-00b4ddbf68d3",
     "alias" : "registration",
     "description" : "registration flow",
     "providerId" : "basic-flow",
@@ -2304,7 +2332,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "f66aecac-f51a-4c80-8869-338d89054615",
+    "id" : "0cdcba23-b485-416e-873b-f1695646bef8",
     "alias" : "registration form",
     "description" : "registration form",
     "providerId" : "form-flow",
@@ -2340,7 +2368,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "7c404e92-1b71-4a64-8d86-763232fc01ea",
+    "id" : "ed2d6f0c-4414-49e4-bda1-217cb40e168f",
     "alias" : "reset credentials",
     "description" : "Reset credentials for a user if they forgot their password or something",
     "providerId" : "basic-flow",
@@ -2376,7 +2404,7 @@
       "userSetupAllowed" : false
     } ]
   }, {
-    "id" : "a69efd34-ba60-4ff2-852a-1704ae3de2a4",
+    "id" : "a5d09fd7-e988-485b-a5e8-bb9a54e34c42",
     "alias" : "saml ecp",
     "description" : "SAML ECP Profile Authentication Flow",
     "providerId" : "basic-flow",
@@ -2392,13 +2420,13 @@
     } ]
   } ],
   "authenticatorConfig" : [ {
-    "id" : "65bc1552-4100-4b2e-b765-4393f09a1af1",
+    "id" : "da63f903-8393-4686-8187-6ca865a79448",
     "alias" : "create unique user config",
     "config" : {
       "require.password.update.after.registration" : "false"
     }
   }, {
-    "id" : "7f26c4ed-6eb2-4cab-8ffa-c4da830ffa26",
+    "id" : "96a14ace-debb-42f0-8dff-701891d6048a",
     "alias" : "review profile config",
     "config" : {
       "update.profile.on.first.login" : "missing"
diff --git a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
index cdec045020c3b5cc554e4fc81d6bfae8087e2a01..68c240908fdd3af73b52ddd6c0263b670910791a 100644
--- a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
+++ b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
@@ -23,6 +23,7 @@ import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import java.security.Principal;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 
@@ -52,10 +53,23 @@ public class ContainerEndpoint {
                                                            @RequestParam(required = false) Integer limit) {
         log.debug("endpoint find all containers, principal={}, limit={}", principal, limit);
         final List<Container> containers = containerService.getAll(limit);
+        final List<com.github.dockerjava.api.model.Container> list = containerService.list();
+        final List<ContainerBriefDto> dtos = containers.stream()
+                .map(containerMapper::containerToDatabaseContainerBriefDto)
+                .peek(container -> {
+                    final Optional<com.github.dockerjava.api.model.Container> optional = list.stream()
+                            .filter(c -> c.getId().equals(container.getHash()))
+                            .findFirst();
+                    optional.ifPresent(value -> {
+                        final String state = value.getState();
+                        log.trace("container {} has status {}", container.getId(), state);
+                        container.setRunning(state.equals("running"));
+                    });
+                })
+                .collect(Collectors.toList());
+        log.trace("find all containers resulted in containers {}", dtos);
         return ResponseEntity.ok()
-                .body(containers.stream()
-                        .map(containerMapper::containerToDatabaseContainerBriefDto)
-                        .collect(Collectors.toList()));
+                .body(dtos);
     }
 
     @PostMapping
diff --git a/fda-container-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java b/fda-container-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
index 57104de0122ab93e82837291854de0ae8c7c1830..335ecdc23d7dc020ac50bb3c7b58668332cf484a 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java
@@ -6,6 +6,7 @@ import at.tuwien.api.container.ContainerDto;
 import at.tuwien.api.container.ContainerStateDto;
 import at.tuwien.entities.container.Container;
 import at.tuwien.entities.container.image.ContainerImage;
+import at.tuwien.entities.user.User;
 import com.github.dockerjava.api.command.InspectContainerResponse;
 import org.mapstruct.*;
 
@@ -14,7 +15,7 @@ import java.util.Locale;
 import java.util.Objects;
 import java.util.regex.Pattern;
 
-@Mapper(componentModel = "spring", uses = {ImageMapper.class, DatabaseMapper.class})
+@Mapper(componentModel = "spring", uses = {ImageMapper.class, DatabaseMapper.class, UserMapper.class})
 public interface ContainerMapper {
 
     org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ContainerMapper.class);
@@ -22,6 +23,7 @@ public interface ContainerMapper {
     default String containerCreateRequestDtoToDockerImage(ContainerCreateRequestDto data) {
         final String image = data.getRepository() + ":" + data.getTag();
         log.trace("mapped container request {} to image {}", data, image);
+        final User user;
         return image;
     }
 
diff --git a/fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
index cfcab8f9975751ae5a3e50dec28285a9f2bd0ddf..d92e24f645f1e7fe23023e350b9a1928c9ee590e 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
@@ -4,7 +4,12 @@ import at.tuwien.api.auth.TokenIntrospectDto;
 import at.tuwien.api.user.GrantedAuthorityDto;
 import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDetailsDto;
+import at.tuwien.api.user.UserDto;
+import at.tuwien.entities.user.User;
+import at.tuwien.entities.user.UserAttribute;
 import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 
@@ -16,6 +21,18 @@ public interface UserMapper {
 
     org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserMapper.class);
 
+    /* keep */
+    @Mappings({
+            @Mapping(target = "orcid", expression = "java(data.getAttributes().stream().filter(a -> a.getName().equals(\"orcid\")).findFirst().get().getValue())")
+    })
+    UserBriefDto userToUserBriefDto(User data);
+
+    /* keep */
+    @Mappings({
+            @Mapping(target = "orcid", expression = "java(data.getAttributes().stream().filter(a -> a.getName().equals(\"orcid\")).findFirst().get().getValue())")
+    })
+    UserDto userToUserDto(User data);
+
     UserDetailsDto userBriefDtoToUserDetailsDto(UserBriefDto data);
 
     default UserDetailsDto tokenIntrospectDtoToUserDetailsDto(TokenIntrospectDto data) {
diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java b/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java
index 26654fc34f51bb974b91036fadeb26eca12a1f55..24400fa3549581fa098fbc101e9b2cfae17fe64f 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java
@@ -63,6 +63,8 @@ public interface ContainerService {
      */
     List<Container> getAll(Integer limit);
 
+    List<com.github.dockerjava.api.model.Container> list();
+
     /**
      * @param containerId
      * @return
diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
index 9753d9687e7ec0113b00bde7cede4a4d3e41b1e6..ff1c9c22a92b423de396384aad61d124118157b0 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java
@@ -32,7 +32,6 @@ import org.springframework.transaction.annotation.Transactional;
 import java.security.Principal;
 import java.util.List;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 @Log4j2
 @Service
@@ -227,6 +226,13 @@ public class ContainerServiceImpl implements ContainerService {
         return containers;
     }
 
+    @Override
+    public List<com.github.dockerjava.api.model.Container> list() {
+        return dockerClient.listContainersCmd()
+                .withShowAll(true)
+                .exec();
+    }
+
     @Override
     @Transactional
     public Container start(Long containerId) throws ContainerNotFoundException,
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
index b8a1b241b3395afa4ddf876576c038ed77247626..77b76c1dd2a59b4bd62033d187717995a4f692a2 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java
@@ -38,6 +38,10 @@ public class ContainerBriefDto {
     @Schema(example = "air-quality")
     private String internalName;
 
+    @NotNull
+    @Schema(example = "true")
+    private Boolean running;
+
     @org.springframework.data.annotation.Transient
     private DatabaseBriefDto database;
 
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerDto.java
index ca2bcded38f067c9927600d7e277a27117120ce8..e4d32aeb5df225b3b74625935640a144dd6a928a 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerDto.java
@@ -46,6 +46,10 @@ public class ContainerDto {
     @JsonProperty("ip_address")
     private String ipAddress;
 
+    @NotNull
+    @Schema(example = "true")
+    private Boolean running;
+
     private ImageBriefDto image;
 
     private Integer port;
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java
index 6d198b70979e860dcec789a96706a479650bb5b4..d11d345a0d66457a56beaacf025b02a15c57a10d 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java
@@ -29,6 +29,9 @@ public class UserBriefDto {
     @Schema(example = "Josiah Carberry")
     private String name;
 
+    @Schema(example = "0000-0002-1825-0097")
+    private String orcid;
+
     @JsonProperty("given_name")
     @Schema(example = "Josiah")
     private String firstname;
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java
index 3796e6c80f13f5d0b3cf6fcb9f15aa88178e61ee..d3b081ade0f4f4a67fdf7c60726ec22d8ef4b20d 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java
@@ -28,6 +28,9 @@ public class UserDto {
     @Schema(example = "Josiah Carberry")
     private String name;
 
+    @Schema(example = "0000-0002-1825-0097")
+    private String orcid;
+
     @JsonProperty("given_name")
     @Schema(example = "Josiah")
     private String firstname;
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/container/Container.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/container/Container.java
index 1286cf7ea7ba36c909924f0c831d1ac96272f2b1..797ffda9926f259af70e630f68b4baac3f4c29a3 100644
--- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/container/Container.java
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/container/Container.java
@@ -3,20 +3,14 @@ package at.tuwien.entities.container;
 import at.tuwien.entities.container.image.ContainerImage;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.user.User;
-import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.*;
 import org.hibernate.annotations.GenericGenerator;
-import org.hibernate.annotations.SQLDelete;
-import org.hibernate.annotations.Where;
 import org.springframework.data.annotation.CreatedDate;
 import org.springframework.data.annotation.LastModifiedDate;
 import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import javax.persistence.*;
 import java.time.Instant;
-import java.util.List;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
 
 @Data
 @Entity
diff --git a/fda-ui/api/authentication.service.js b/fda-ui/api/authentication.service.js
index 43bbf8274277da3ef53d03edddb200dd8edef9f4..33dcadd1f25e9dfe138247b46eee372f25767296 100644
--- a/fda-ui/api/authentication.service.js
+++ b/fda-ui/api/authentication.service.js
@@ -65,11 +65,9 @@ class AuthenticationService {
         const authentication = response.data
         // eslint-disable-next-line camelcase
         const { access_token, refresh_token } = authentication
-        console.debug('response authenticate', authentication)
         store().commit('SET_TOKEN', access_token)
         store().commit('SET_REFRESH_TOKEN', refresh_token)
-        const user = UserMapper.tokenToUser(access_token)
-        store().commit('SET_USER', user)
+        store().commit('SET_ROLES', UserMapper.tokenToRoles(access_token))
         resolve(authentication)
       }).catch((error) => {
         console.error('Failed to authenticate', error)
diff --git a/fda-ui/api/container.service.js b/fda-ui/api/container.service.js
index 34e069a804f4499a57f9cda1b40752530b9d12e0..48adb5427bad97840ba73756d9683d50f40c730c 100644
--- a/fda-ui/api/container.service.js
+++ b/fda-ui/api/container.service.js
@@ -26,7 +26,8 @@ class ContainerService {
           const container = response.data
           console.debug('response container', container)
           resolve(container)
-        }).catch((error) => {
+        })
+        .catch((error) => {
           const { code, message } = error
           console.error('Failed to load container', error)
           Vue.$toast.error(`[${code}] Failed to load container: ${message}`)
@@ -42,7 +43,8 @@ class ContainerService {
           const container = response.data
           console.debug('response container', container)
           resolve(container)
-        }).catch((error) => {
+        })
+        .catch((error) => {
           const { code, message } = error
           console.error('Failed to create container', error)
           Vue.$toast.error(`[${code}] Failed to create container: ${message}`)
@@ -58,11 +60,18 @@ class ContainerService {
           const container = response.data
           console.debug('response container', container)
           resolve(container)
-        }).catch((error) => {
-          const { code, message } = error
-          console.error('Failed to modify container', error)
-          Vue.$toast.error(`[${code}] Failed to modify container: ${message}`)
-          reject(error)
+        })
+        .catch((error) => {
+          const { code, message, response } = error
+          const { status } = response
+          if (status === 409) {
+            console.warn('Failed to modify container', error)
+            reject(error)
+          } else {
+            console.error('Failed to modify container', error)
+            Vue.$toast.error(`[${code}] Failed to modify container: ${message}`)
+            reject(error)
+          }
         })
     })
   }
diff --git a/fda-ui/api/database.service.js b/fda-ui/api/database.service.js
new file mode 100644
index 0000000000000000000000000000000000000000..1d0273c505a988ead4dd6338065ea92f8129de9a
--- /dev/null
+++ b/fda-ui/api/database.service.js
@@ -0,0 +1,147 @@
+import Vue from 'vue'
+import api from '@/api'
+
+class DatabaseService {
+  findAll (id) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/container/${id}/database`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const databases = response.data
+          console.debug('response databases', databases)
+          resolve(databases)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load databases', error)
+          Vue.$toast.error(`[${code}] Failed to load databases: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  findOne (id, databaseId) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/container/${id}/database/${databaseId}`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const database = response.data
+          console.debug('response database', database)
+          resolve(database)
+        }).catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load database', error)
+          Vue.$toast.error(`[${code}] Failed to load database: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  create (id, data) {
+    return new Promise((resolve, reject) => {
+      api.post(`/api/container/${id}/database`, data, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const database = response.data
+          console.debug('response database', database)
+          resolve(database)
+        }).catch((error) => {
+          const { code, message } = error
+          console.error('Failed to create database', error)
+          Vue.$toast.error(`[${code}] Failed to create database: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  modifyVisibility (id, databaseId, isPublic) {
+    return new Promise((resolve, reject) => {
+      api.put(`/api/container/${id}/database/${databaseId}/visibility`, { is_public: isPublic }, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const database = response.data
+          console.debug('response database', database)
+          resolve(database)
+        }).catch((error) => {
+          const { code, message } = error
+          console.error('Failed to modify database visibility', error)
+          Vue.$toast.error(`[${code}] Failed to modify database visibility: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  modifyOwner (id, databaseId, username) {
+    return new Promise((resolve, reject) => {
+      api.put(`/api/container/${id}/database/${databaseId}/transfer`, { username }, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const database = response.data
+          console.debug('response database', database)
+          resolve(database)
+        }).catch((error) => {
+          const { code, message } = error
+          console.error('Failed to modify database owner', error)
+          Vue.$toast.error(`[${code}] Failed to modify database owner: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  checkAccess (id, databaseId) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/container/${id}/database/${databaseId}/access`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const databases = response.data
+          console.debug('response databases', databases)
+          resolve(databases)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to check database access', error)
+          Vue.$toast.error(`[${code}] Failed to check database access: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  modifyAccess (id, databaseId, username, type) {
+    return new Promise((resolve, reject) => {
+      api.put(`/api/container/${id}/database/${databaseId}/access/${username}`, { type }, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const database = response.data
+          console.debug('response database', database)
+          resolve(database)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to modify database access', error)
+          Vue.$toast.error(`[${code}] Failed to modify database access: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  revokeAccess (id, databaseId, username) {
+    return new Promise((resolve, reject) => {
+      api.delete(`/api/container/${id}/database/${databaseId}/access/${username}`, { headers: { Accept: 'application/json' } })
+        .then(() => resolve())
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to revoke database access', error)
+          Vue.$toast.error(`[${code}] Failed to revoke database access: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  giveAccess (id, databaseId, username, type) {
+    return new Promise((resolve, reject) => {
+      api.post(`/api/container/${id}/database/${databaseId}/access/${username}`, { username, type }, { headers: { Accept: 'application/json' } })
+        .then(() => resolve())
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to give database access', error)
+          Vue.$toast.error(`[${code}] Failed to give database access: ${message}`)
+          reject(error)
+        })
+    })
+  }
+}
+
+export default new DatabaseService()
diff --git a/fda-ui/api/database/index.js b/fda-ui/api/database/index.js
deleted file mode 100644
index dee8179bf5dbfefba9426f060ebef5664caa4e49..0000000000000000000000000000000000000000
--- a/fda-ui/api/database/index.js
+++ /dev/null
@@ -1,43 +0,0 @@
-const axios = require('axios/dist/browser/axios.cjs')
-
-export function createDatabase (token, container) {
-  const payload = {
-    name: container.name,
-    is_public: container.is_public ? container.is_public : true
-  }
-  return axios.post(`/api/container/${container.id}/database`, payload, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function modifyVisibility (token, containerId, databaseId, isPublic) {
-  const payload = {
-    is_public: isPublic
-  }
-  return axios.put(`/api/container/${containerId}/database/${databaseId}/visibility`, payload, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function modifyOwnership (token, containerId, databaseId, username) {
-  const payload = {
-    username
-  }
-  return axios.put(`/api/container/${containerId}/database/${databaseId}/transfer`, payload, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function findDatabase (token, containerId, databaseId) {
-  return axios.get(`/api/container/${containerId}/database/${databaseId}`, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
diff --git a/fda-ui/api/identifier.service.js b/fda-ui/api/identifier.service.js
new file mode 100644
index 0000000000000000000000000000000000000000..549cd0eabd4e9282ead1788e44fbdf2d9d780268
--- /dev/null
+++ b/fda-ui/api/identifier.service.js
@@ -0,0 +1,23 @@
+import Vue from 'vue'
+import api from '@/api'
+
+class IdentifierService {
+  findPid (id) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/pid/${id}`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const identifier = response.data
+          console.debug('response identifier', identifier)
+          resolve(identifier)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load identifier', error)
+          Vue.$toast.error(`[${code}] Failed to load identifier: ${message}`)
+          reject(error)
+        })
+    })
+  }
+}
+
+export default new IdentifierService()
diff --git a/fda-ui/api/query.service.js b/fda-ui/api/query.service.js
new file mode 100644
index 0000000000000000000000000000000000000000..8fc66756bacb5c95f7be93600f68c5438ea86d18
--- /dev/null
+++ b/fda-ui/api/query.service.js
@@ -0,0 +1,73 @@
+import Vue from 'vue'
+import api from '@/api'
+
+class QueryService {
+  findAll (id, databaseId) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/container/${id}/database/${databaseId}/query`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const queries = response.data
+          console.debug('response queries', queries)
+          resolve(queries)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load queries', error)
+          Vue.$toast.error(`[${code}] Failed to load queries: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  findOne (id, databaseId, queryId) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/container/${id}/database/${databaseId}/query/${queryId}`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const query = response.data
+          console.debug('response query', query)
+          resolve(query)
+        }).catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load query', error)
+          Vue.$toast.error(`[${code}] Failed to load query: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  persist (id, databaseId, queryId) {
+    return new Promise((resolve, reject) => {
+      api.put(`/api/container/${id}/database/${databaseId}/query/${queryId}`, {}, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const query = response.data
+          console.debug('response query', query)
+          resolve(query)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to persist query', error)
+          Vue.$toast.error(`[${code}] Failed to persist query: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  export (id, databaseId, queryId) {
+    return new Promise((resolve, reject) => {
+      api.put(`/api/container/${id}/database/${databaseId}/query/${queryId}/export`, {}, { headers: { Accept: 'text/csv' } })
+        .then((response) => {
+          const query = response.data
+          console.debug('response export', query)
+          resolve(query)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to export query', error)
+          Vue.$toast.error(`[${code}] Failed to export query: ${message}`)
+          reject(error)
+        })
+    })
+  }
+}
+
+export default new QueryService()
diff --git a/fda-ui/api/query/index.js b/fda-ui/api/query/index.js
deleted file mode 100644
index e76cc2da4fb545a56bcf506e94018f2469a05315..0000000000000000000000000000000000000000
--- a/fda-ui/api/query/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const axios = require('axios/dist/browser/axios.cjs')
-
-export function findQuery (token, containerId, databaseId, queryId) {
-  return axios.get(`/api/container/${containerId}/database/${databaseId}/query/${queryId}`, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function persistQuery (token, containerId, databaseId, queryId) {
-  return axios.put(`/api/container/${containerId}/database/${databaseId}/query/${queryId}`, {}, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
diff --git a/fda-ui/api/table.service.js b/fda-ui/api/table.service.js
new file mode 100644
index 0000000000000000000000000000000000000000..36a932200a39debe8fe7ab9d135089a2d8348f9d
--- /dev/null
+++ b/fda-ui/api/table.service.js
@@ -0,0 +1,79 @@
+import Vue from 'vue'
+import api from '@/api'
+
+/**
+ * Service class for interaction with Table Service in the back end.
+ *
+ * @author Martin Weise
+ */
+class TableService {
+  findAll (id, databaseId) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/container/${id}/database/${databaseId}/table`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const tables = response.data
+          console.debug('response tables', tables)
+          resolve(tables)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load tables', error)
+          Vue.$toast.error(`[${code}] Failed to load tables: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  findOne (id, databaseId, tableId) {
+    return new Promise((resolve, reject) => {
+      api.get(`/api/container/${id}/database/${databaseId}/table/${tableId}`, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const table = response.data
+          console.debug('response table', table)
+          resolve(table)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to load table', error)
+          Vue.$toast.error(`[${code}] Failed to load table: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  create (id, databaseId, data) {
+    return new Promise((resolve, reject) => {
+      api.post(`/api/container/${id}/database/${databaseId}/table`, data, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const table = response.data
+          console.debug('response table', table)
+          resolve(table)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to create table', error)
+          Vue.$toast.error(`[${code}] Failed to create table: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
+  importCsv (id, databaseId, tableId, data) {
+    return new Promise((resolve, reject) => {
+      api.post(`/api/container/${id}/database/${databaseId}/table/${tableId}/import`, data, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const table = response.data
+          console.debug('response table', table)
+          resolve(table)
+        })
+        .catch((error) => {
+          const { code, message } = error
+          console.error('Failed to import csv to table', error)
+          Vue.$toast.error(`[${code}] Failed to import csv to table: ${message}`)
+          reject(error)
+        })
+    })
+  }
+}
+
+export default new TableService()
diff --git a/fda-ui/api/table/index.js b/fda-ui/api/table/index.js
deleted file mode 100644
index 097d003972837b4d640125704831315256360bfb..0000000000000000000000000000000000000000
--- a/fda-ui/api/table/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const axios = require('axios/dist/browser/axios.cjs')
-
-export function listTables (token, containerId, databaseId) {
-  return axios.get(`/api/container/${containerId}/database/${databaseId}/table`, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function createTable (token, containerId, databaseId, payload) {
-  return axios.post(`/api/container/${containerId}/database/${databaseId}/table`, payload, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function dataImport (token, containerId, databaseId, tableId, payload) {
-  return axios.post(`/api/container/${containerId}/database/${databaseId}/table/${tableId}/data/import`, payload, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
diff --git a/fda-ui/api/user.mapper.js b/fda-ui/api/user.mapper.js
index dec8f31910d956c07a2946ae3416b56d8be3098d..31a690e509785299c785fc22ff116c0ab513b448 100644
--- a/fda-ui/api/user.mapper.js
+++ b/fda-ui/api/user.mapper.js
@@ -1,31 +1,24 @@
 import jwtDecode from 'jwt-decode'
 
 class UserMapper {
-  tokenToUser (token) {
+  tokenToRoles (token) {
     const data = jwtDecode(token)
-    return {
-      id: data.sub,
-      firstname: data.given_name || null,
-      lastname: data.family_name || null,
-      username: data.client_id,
-      roles: data.realm_access.roles || [],
-      attributes: data.attributes || []
-    }
+    return data.realm_access.roles || []
   }
 
-  tokenToRoles (token) {
+  tokenToUserId (token) {
     const data = jwtDecode(token)
-    if (!data) {
-      return []
-    }
-    return data.realm_access.roles || []
+    return data.sub
   }
 
-  getThemeDark (user) {
-    if (!user || !user.attributes || user.attributes.filter(a => a.name === 'theme_dark').length === 0) {
-      return false
+  userInfoToUser (data) {
+    const obj = Object.assign({}, data)
+    obj.attributes = {
+      theme_dark: data.attributes.filter(a => a.name === 'theme_dark')[0].value === 'true',
+      orcid: data.attributes.filter(a => a.name === 'orcid')[0].value,
+      affiliation: data.attributes.filter(a => a.name === 'affiliation')[0].value
     }
-    return user.attributes.filter(a => a.name === 'theme_dark')[0].value === 'true'
+    return obj
   }
 }
 
diff --git a/fda-ui/api/user.service.js b/fda-ui/api/user.service.js
index c86f1b938972077337916c072f793fb3eb724542..e324cf68f3b351bca19cade29fe1aedd388d5f49 100644
--- a/fda-ui/api/user.service.js
+++ b/fda-ui/api/user.service.js
@@ -1,5 +1,6 @@
 import Vue from 'vue'
 import api from '@/api'
+import UserMapper from '@/api/user.mapper'
 
 class UserService {
   findAll () {
@@ -23,8 +24,8 @@ class UserService {
     return new Promise((resolve, reject) => {
       api.get(`/api/user/${id}`, { headers: { Accept: 'application/json' } })
         .then((response) => {
-          const user = response.data
-          console.debug('response user', user)
+          const user = UserMapper.userInfoToUser(response.data)
+          console.debug('response user', response.data, 'mapped user', user)
           resolve(user)
         }).catch((error) => {
           const { code, message } = error
@@ -35,6 +36,22 @@ class UserService {
     })
   }
 
+  updateInformation (id, data) {
+    return new Promise((resolve, reject) => {
+      api.put(`/api/user/${id}`, data, { headers: { Accept: 'application/json' } })
+        .then((response) => {
+          const user = UserMapper.userInfoToUser(response.data)
+          console.debug('response user', response.data, 'mapped user', user)
+          resolve(user)
+        }).catch((error) => {
+          const { code, message } = error
+          console.error('Failed to update user information', error)
+          Vue.$toast.error(`[${code}] Failed to update user information: ${message}`)
+          reject(error)
+        })
+    })
+  }
+
   create (data) {
     return new Promise((resolve, reject) => {
       api.post('/api/user', data, { headers: { Accept: 'application/json' } })
@@ -63,7 +80,7 @@ class UserService {
 
   updatePassword (id, password) {
     return new Promise((resolve, reject) => {
-      api.post(`/api/user/${id}/password`, { password }, { headers: { Accept: 'application/json' } })
+      api.put(`/api/user/${id}/password`, { password }, { headers: { Accept: 'application/json' } })
         .then(() => resolve())
         .catch((error) => {
           const { code, message } = error
@@ -76,7 +93,7 @@ class UserService {
 
   updateTheme (id, themeDark) {
     return new Promise((resolve, reject) => {
-      api.post(`/api/user/${id}/theme`, { theme_dark: themeDark }, { headers: { Accept: 'application/json' } })
+      api.put(`/api/user/${id}/theme`, { theme_dark: themeDark }, { headers: { Accept: 'application/json' } })
         .then(() => resolve())
         .catch((error) => {
           const { code, message } = error
diff --git a/fda-ui/api/user/index.js b/fda-ui/api/user/index.js
deleted file mode 100644
index b313891ff34081f2c91e94d52e26ff1112c1325d..0000000000000000000000000000000000000000
--- a/fda-ui/api/user/index.js
+++ /dev/null
@@ -1,89 +0,0 @@
-// eslint-disable-next-line camelcase
-import jwt_decode from 'jwt-decode'
-import api from '../index'
-const qs = require('qs')
-
-export function updateUser (token, userId, data) {
-  return api.put(`/api/user/${userId}`, data, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function updateUserPassword (token, userId, password) {
-  const payload = {
-    password
-  }
-  return api.put(`/api/user/${userId}/password`, payload, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function toggleUserTheme (token, userId, themeDark) {
-  const payload = {
-    theme_dark: themeDark
-  }
-  return api.put(`/api/user/${userId}/theme`, payload, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function findUser (token) {
-  const user = tokenToUser(token)
-  return api.get(`/api/user/${user.id}`, {
-    headers: {
-      Authorization: `Bearer ${token}`
-    }
-  })
-}
-
-export function refresh (clientSecret, token) {
-  const payload = {
-    client_id: 'dbrepo-client',
-    grant_type: 'refresh_token',
-    client_secret: clientSecret,
-    refresh_token: token
-  }
-  return api.post('/api/auth/realms/dbrepo/protocol/openid-connect/token', qs.stringify(payload), {
-    headers: { ContentType: 'application/form-data' }
-  })
-}
-
-export function tokenToUser (token) {
-  const data = jwt_decode(token)
-  return {
-    id: data.sub,
-    firstname: data.given_name || null,
-    lastname: data.family_name || null,
-    username: data.client_id,
-    roles: data.realm_access.roles || []
-  }
-}
-
-export function tokenToExp (token) {
-  const data = jwt_decode(token)
-  if (!data) {
-    return new Date()
-  }
-  return new Date(data.exp * 1000)
-}
-
-export function tokenToRoles (token) {
-  const data = jwt_decode(token)
-  if (!data) {
-    return []
-  }
-  return data.realm_access.roles || []
-}
-
-export function getThemeDark (user) {
-  if (!user || !user.attributes || user.attributes.filter(a => a.name === 'theme_dark').length === 0) {
-    return false
-  }
-  return user.attributes.filter(a => a.name === 'theme_dark')[0].value === 'true'
-}
diff --git a/fda-ui/components/DatabaseList.vue b/fda-ui/components/DatabaseList.vue
index 01d50e8cef1cf3d407cffffee21fc2ee79d2d424..7dab9d6bddd8e3b203ed650cd8840320b7666d90 100644
--- a/fda-ui/components/DatabaseList.vue
+++ b/fda-ui/components/DatabaseList.vue
@@ -27,14 +27,23 @@
         </div>
         <div v-text="identifierDescription(container)" />
       </v-card-text>
-      <v-card-text v-if="canInit(container)" class="db-buttons">
+      <v-card-text v-if="needsStart(container) || needsDatabase(container)" class="db-buttons">
         <v-btn
+          v-if="needsStart(container)"
           small
           secondary
           :loading="container?.loading"
-          @click.stop="initDatabase(container)">
+          @click.stop="startContainer(container).then(() => createDatabase(container))">
           Start
         </v-btn>
+        <v-btn
+          v-else-if="needsDatabase(container)"
+          small
+          secondary
+          :loading="container?.loading"
+          @click.stop="createDatabase(container)">
+          Create Database
+        </v-btn>
       </v-card-text>
     </v-card>
     <v-toolbar v-if="false" flat>
@@ -51,7 +60,7 @@
 
 <script>
 import { formatCreators, formatUser, formatYearUTC, isResearcher } from '@/utils'
-import { createDatabase } from '@/api/database'
+import DatabaseService from '@/api/database.service'
 import ContainerService from '@/api/container.service'
 
 export default {
@@ -107,7 +116,16 @@ export default {
       const creators = formatCreators(container)
       return creators || this.formatUser(container.creator)
     },
-    canInit (container) {
+    needsStart (container) {
+      if (!this.user) {
+        return false
+      }
+      if (container.creator.username !== this.user.username) {
+        return false
+      }
+      return container.running === false
+    },
+    needsDatabase (container) {
       if (!this.user) {
         return false
       }
@@ -122,10 +140,6 @@ export default {
     hasIdentifier (container) {
       return container.database && container.database.identifier
     },
-    async initDatabase (container) {
-      await this.startContainer(container)
-        .then(() => this.createDatabase(container))
-    },
     identifierCreated (container) {
       if (!container || !container.database || !container.database.identifier) {
         return null
@@ -148,26 +162,23 @@ export default {
         })
       this.loadingContainers = false
     },
-    async startContainer (container) {
+    startContainer (container) {
       container.loading = true
-      await ContainerService.modify(container.id, 'start')
-      container.loading = false
+      return new Promise((resolve, reject) => {
+        ContainerService.modify(container.id, 'start')
+          .then(() => resolve())
+          .finally(() => {
+            container.loading = false
+          })
+      })
     },
-    async createDatabase (container) {
-      try {
-        container.loading = true
-        const res = await createDatabase(this.token, container)
-        container.database = res.data
-        console.debug('created database', container.database)
-        this.error = false
-      } catch (error) {
-        console.error('create database', error)
-        const { message } = error.response
-        this.error = true
-        console.error('Failed to create database', error)
-        this.$toast.error(`${message}`)
-      }
-      container.loading = false
+    createDatabase (container) {
+      container.loading = true
+      DatabaseService.create(container.id, { name: container.name, is_public: true })
+        .then((database) => {
+          container.loading = false
+          this.$router.push(`/container/${container.id}/database/${database.id}`)
+        })
     },
     link (container) {
       if (!container.database || !container.database.id) {
diff --git a/fda-ui/components/dialogs/CreateDB.vue b/fda-ui/components/dialogs/CreateDB.vue
index 44adbbdb217cd94bf2784108a7d053f678614954..b2877b02809394dfec9831d4d500fa76f442a3f1 100644
--- a/fda-ui/components/dialogs/CreateDB.vue
+++ b/fda-ui/components/dialogs/CreateDB.vue
@@ -56,7 +56,7 @@
 <script>
 import { notEmpty } from '@/utils'
 import ContainerService from '@/api/container.service'
-import { createDatabase } from '@/api/database'
+import DatabaseService from '@/api/database.service'
 
 export default {
   data () {
@@ -139,35 +139,41 @@ export default {
         .then(() => this.startContainer(this.container)
           .then(() => this.createDatabase(this.container)))
     },
-    async createContainer () {
+    createContainer () {
       this.createContainerDto.repository = this.engine.repository
       this.createContainerDto.tag = this.engine.tag
       this.loading = true
-      this.container = await ContainerService.create(this.createContainerDto)
-      this.error = false
-      this.loading = false
+      return new Promise((resolve, reject) => {
+        ContainerService.create(this.createContainerDto)
+          .then((container) => {
+            this.container = container
+            this.loading = false
+            resolve(container)
+          })
+          .catch(error => reject(error))
+      })
     },
-    async startContainer (container) {
+    startContainer (container) {
       this.loading = true
-      await ContainerService.modify(container.id, 'start')
-      this.loading = false
+      return new Promise((resolve, reject) => {
+        ContainerService.modify(container.id, 'start')
+          .then(() => {
+            this.loading = false
+            resolve()
+          })
+          .catch(error => reject(error))
+      })
     },
-    async createDatabase (container) {
-      try {
-        this.loading = true
-        this.createDatabaseDto.id = container.id
-        this.createDatabaseDto.name = container.name
-        const res = await createDatabase(this.token, this.createDatabaseDto)
-        container.database = res.data
-        console.debug('created database', container.database)
-        this.error = false
-        this.$emit('close', { success: true })
-      } catch (error) {
-        console.error('create database', error)
-        this.error = true
-        this.$toast.error('Failed to create database')
-      }
-      this.loading = false
+    createDatabase (container) {
+      this.loading = true
+      DatabaseService.create(container.id, { name: container.name, is_public: true })
+        .then((database) => {
+          container.database = database
+          this.$emit('close', { success: true })
+        })
+        .finally(() => {
+          this.loading = false
+        })
     },
     notEmpty
   }
diff --git a/fda-ui/components/dialogs/EditAccess.vue b/fda-ui/components/dialogs/EditAccess.vue
index bae918a20f67726c7e91896837d3137f38b8dc4d..5d063ca56bd86f2687072453368dd5499a91077f 100644
--- a/fda-ui/components/dialogs/EditAccess.vue
+++ b/fda-ui/components/dialogs/EditAccess.vue
@@ -21,7 +21,7 @@
             <v-col>
               <v-autocomplete
                 v-model="modify.username"
-                :items="eligableUsers"
+                :items="eligibleUsers"
                 :loading="loadingUsers"
                 :rules="[v => !!v || $t('Required')]"
                 required
@@ -66,6 +66,8 @@
         </v-card-actions>
       </v-card>
     </v-form>
+    <pre>{{ eligibleUsers }}</pre>
+    <pre>{{ modify.username }}</pre>
   </div>
 </template>
 
@@ -77,6 +79,12 @@ export default {
       default () {
         return null
       }
+    },
+    accessType: {
+      type: String,
+      default () {
+        return null
+      }
     }
   },
   data () {
@@ -126,7 +134,11 @@ export default {
       }
       return this.types
     },
-    eligableUsers () {
+    eligibleUsers () {
+      if (this.accessType) {
+        /* this is a modification, list only the edited user as eligible */
+        return [{ username: this.username, id: '00000' }]
+      }
       return this.users.filter(u => !this.database.accesses.map(a => a.user.id).includes(u.id))
     },
     buttonColor () {
@@ -155,16 +167,15 @@ export default {
     }
   },
   watch: {
-    username (val) {
-      if (!val || this.users.length === 0) {
-        this.modify.username = null
-      }
-      this.selectUser()
+    username () {
+      this.init()
+    },
+    accessType () {
+      this.init()
     }
   },
   mounted () {
-    this.loadUsers()
-      .then(() => this.selectUser())
+    this.init()
   },
   methods: {
     submit () {
@@ -248,11 +259,20 @@ export default {
       }
       this.loadingUsers = false
     },
-    selectUser () {
-      const optional = this.users.filter(u => u.username === this.username)
-      if (optional.length > 0) {
-        this.modify.username = optional[0]
+    init () {
+      if (!this.username) {
+        this.modify.username = null
+        this.loadUsers()
+      } else {
+        this.modify.username = this.username
+        /* eligible users are computed separately */
+      }
+      if (!this.accessType) {
+        this.modify.type = null
+      } else {
+        this.modify.type = this.accessType
       }
+      this.$refs.form.reset()
     }
   }
 }
diff --git a/fda-ui/components/icons/OrcidIcon.vue b/fda-ui/components/icons/OrcidIcon.vue
index 39714ddbf8917245c24d531073038d81cfee4f02..ed3b7d72d0ff83b07b06f151ea09f74f7dbf0214 100644
--- a/fda-ui/components/icons/OrcidIcon.vue
+++ b/fda-ui/components/icons/OrcidIcon.vue
@@ -1,5 +1,5 @@
 <template>
-  <a :href="link">
+  <a :href="link" target="_blank">
     <svg xmlns="http://www.w3.org/2000/svg" width="16" fill="#a6ce39" viewBox="0 0 512 512">
       <!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
       <path
diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue
index 9b8acb966419c1c31d365b74716070ab7c299d86..e7f52db13a801355b2c8dfdd9f623e3c097117ad 100644
--- a/fda-ui/layouts/default.vue
+++ b/fda-ui/layouts/default.vue
@@ -54,43 +54,48 @@
           <v-icon>mdi-magnify</v-icon>
         </v-btn>
         <v-spacer />
-        <v-btn
-          v-if="!token"
-          class="mr-2"
-          color="secondary"
-          to="/login">
-          <v-icon left>mdi-login</v-icon> Login
-        </v-btn>
-        <v-btn
-          v-if="!token"
-          class="mr-2"
-          color="primary"
-          to="/signup">
-          <v-icon left>mdi-account-plus</v-icon> Signup
-        </v-btn>
-        <v-menu v-if="user" bottom offset-y left>
-          <template v-slot:activator="{ on, attrs }">
-            <v-btn
-              icon
-              v-bind="attrs"
-              v-on="on">
-              <v-icon>mdi-dots-vertical</v-icon>
-            </v-btn>
-          </template>
-          <v-list>
-            <v-list-item
-              v-for="locale in availableLocales"
-              :key="locale.code"
-              :to="switchLocalePath(locale.code)">
-              <v-list-item-title>{{ locale.name }}</v-list-item-title>
-            </v-list-item>
-            <v-list-item
-              v-if="token"
-              @click="logout">
-              Logout
-            </v-list-item>
-          </v-list>
-        </v-menu>
+        <div v-if="!user">
+          <v-btn
+            class="mr-2"
+            color="secondary"
+            to="/login">
+            <v-icon left>mdi-login</v-icon> Login
+          </v-btn>
+          <v-btn
+            class="mr-2"
+            color="primary"
+            to="/signup">
+            <v-icon left>mdi-account-plus</v-icon> Signup
+          </v-btn>
+        </div>
+        <div v-else>
+          <v-btn to="/user" plain>
+            {{ user.username }}
+          </v-btn>
+          <v-menu bottom offset-y left>
+            <template v-slot:activator="{ on, attrs }">
+              <v-btn
+                icon
+                v-bind="attrs"
+                v-on="on">
+                <v-icon>mdi-dots-vertical</v-icon>
+              </v-btn>
+            </template>
+            <v-list>
+              <v-list-item
+                v-for="locale in availableLocales"
+                :key="locale.code"
+                :to="switchLocalePath(locale.code)">
+                <v-list-item-title>{{ locale.name }}</v-list-item-title>
+              </v-list-item>
+              <v-list-item
+                v-if="token"
+                @click="logout">
+                Logout
+              </v-list-item>
+            </v-list>
+          </v-menu>
+        </div>
       </v-app-bar>
     </v-form>
     <v-main>
@@ -111,16 +116,20 @@
         </v-card-text>
       </v-card>
     </v-footer>
-    <pre>{{ $store.state }}</pre>
   </v-app>
 </template>
 
 <script>
 import { isDeveloper } from '@/utils'
 import AuthenticationService from '@/api/authentication.service'
+import DatabaseService from '@/api/database.service'
+import TableService from '@/api/table.service'
+import IdentifierService from '@/api/identifier.service'
 
 export default {
   name: 'DefaultLayout',
+  components: {
+  },
   data () {
     return {
       drawer: false,
@@ -203,9 +212,6 @@ export default {
     },
     '$route.params.database_id': {
       handler (id, oldId) {
-        if (this.user) {
-          this.setTheme()
-        }
         if (id !== oldId) {
           this.loadDatabase()
           // this.loadAccess()
@@ -225,17 +231,16 @@ export default {
     }
   },
   mounted () {
-    // this.loadUser()
-    // this.setTheme()
-    // this.loadDatabase()
-    //   .then(() => {
-    // this.loadIdentifier()
-    // this.loadTable()
-    // })
-    // this.loadAccess()
+    if (this.refreshToken) {
+      AuthenticationService.authenticateToken(this.refreshToken)
+    }
     if (this.$route.query && this.$route.query.q) {
       this.search = this.$route.query.q
     }
+    if (!this.user) {
+      return
+    }
+    this.$vuetify.theme.dark = this.user.attributes.theme_dark
   },
   methods: {
     submit () {
@@ -257,119 +262,68 @@ export default {
       this.$vuetify.theme.dark = false
       this.$router.push('/container')
     },
-    // async loadUser () {
-    //   if (!this.token) {
-    //     return
-    //   }
-    //   try {
-    //     this.loadingUser = true
-    //     const res = await findUser(this.token)
-    //     const user = res.data
-    //     console.debug('user', user)
-    //     this.$store.commit('SET_USER', user)
-    //     const roles = tokenToRoles(this.token)
-    //     this.$store.commit('SET_ROLES', roles)
-    //     this.$vuetify.theme.dark = getThemeDark(user)
-    //     this.loading = false
-    //   } catch (error) {
-    //     console.error('Failed to load user', error)
-    //     const { status } = error.response
-    //     if (status === 401) {
-    //       console.error('Token expired', error)
-    //       this.$toast.warning('Login has expired')
-    //       this.logout()
-    //     } else {
-    //       console.error('user data', error)
-    //       this.$toast.error('Failed to load user')
-    //       this.error = true
-    //     }
-    //   }
-    //   this.loadingUser = false
-    // },
-    // async loadDatabase () {
-    //   if (!this.$route.params.container_id || !this.$route.params.database_id) {
-    //     return
-    //   }
-    //   try {
-    //     this.loading = true
-    //     const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}`, this.config)
-    //     this.$store.commit('SET_DATABASE', res.data)
-    //     console.debug('database', this.database)
-    //   } catch (err) {
-    //     console.error('Could not load database', err)
-    //     this.$toast.error('Could not load database')
-    //   }
-    //   this.loading = false
-    // },
-    // async loadTable () {
-    //   if (!this.$route.params.container_id || !this.$route.params.database_id || !this.$route.params.table_id) {
-    //     return
-    //   }
-    //   try {
-    //     this.loading = true
-    //     const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}`, this.config)
-    //     this.$store.commit('SET_TABLE', res.data)
-    //     console.debug('table', this.table)
-    //   } catch (error) {
-    //     const { status } = error.response
-    //     if (status === 405) {
-    //       const table = this.database.tables.filter(t => t.id === Number(this.$route.params.table_id))[0]
-    //       this.$store.commit('SET_TABLE', table)
-    //     } else {
-    //       const { message } = error.response.data
-    //       console.error('Failed to load table', error)
-    //       this.$toast.error(`Failed to load table: ${message}`)
-    //     }
-    //   }
-    //   this.loading = false
-    // },
-    // async loadAccess () {
-    //   if (!this.$route.params.container_id || !this.$route.params.database_id) {
-    //     return
-    //   }
-    //   if (!this.token) {
-    //     return
-    //   }
-    //   try {
-    //     this.loading = true
-    //     const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/access`, this.config)
-    //     this.access = res.data
-    //     this.$store.commit('SET_ACCESS', res.data)
-    //     console.debug('access', this.access)
-    //   } catch (err) {
-    //     this.$store.commit('SET_ACCESS', null)
-    //     const { status } = err.response
-    //     if (status !== 401 && status !== 403) {
-    //       console.error('Failed to check access', err)
-    //       this.$toast.error('Failed to check access')
-    //     }
-    //   }
-    //   this.loading = false
-    // },
-    // async loadIdentifier () {
-    //   if (!this.database || 'identifier' in this.database) {
-    //     return
-    //   }
-    //   try {
-    //     this.loading = true
-    //     const res = await this.$axios.get(`/api/pid/${this.database.identifier.id}`, this.config)
-    //     const db = this.database
-    //     db.identifier = res.data
-    //     this.$store.commit('SET_DATABASE', db)
-    //   } catch (err) {
-    //     console.error('Failed to load identifier', err)
-    //     this.$toast.error('Failed to load identifier')
-    //   }
-    //   this.loading = false
-    // },
-    retrieve () {
-      this.$router.push({ path: '/search', query: { q: this.search } })
+    loadDatabase () {
+      if (!this.$route.params.container_id || !this.$route.params.database_id) {
+        this.$store.commit('SET_DATABASE', null)
+        return
+      }
+      this.loading = true
+      DatabaseService.findOne(this.$route.params.container_id, this.$route.params.database_id)
+        .then((database) => {
+          this.$store.commit('SET_DATABASE', database)
+          this.loading = false
+          this.loadTable()
+        })
+        .catch(() => {
+          this.loading = false
+        })
     },
-    setTheme () {
-      if (!this.user || !this.user.theme_dark) {
+    loadTable () {
+      if (!this.$route.params.container_id || !this.$route.params.database_id || !this.$route.params.table_id) {
         return
       }
-      this.$vuetify.theme.dark = this.user.theme_dark
+      this.loading = true
+      TableService.findOne(this.$route.params.container_id, this.$route.params.database_id, this.$route.params.table_id)
+        .then((table) => {
+          this.$store.commit('SET_TABLE', table)
+        })
+        .finally(() => {
+          this.loading = false
+        })
+    },
+    loadAccess () {
+      if (!this.$route.params.container_id || !this.$route.params.database_id) {
+        return
+      }
+      if (!this.token) {
+        return
+      }
+      this.loading = true
+      DatabaseService.checkAccess(this.$route.params.container_id, this.$route.params.database_id)
+        .then((access) => {
+          this.$store.commit('SET_ACCESS', access)
+          this.loading = false
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    loadIdentifier () {
+      if (!this.database || 'identifier' in this.database) {
+        return
+      }
+      this.loading = true
+      IdentifierService.findPid(this.database.identifier.id)
+        .then((identifier) => {
+          this.database.identifier = identifier
+          this.$store.commit('SET_DATABASE', this.database)
+        })
+        .finally(() => {
+          this.loading = false
+        })
+    },
+    retrieve () {
+      this.$router.push({ path: '/search', query: { q: this.search } })
     }
   }
 }
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
index 264b049ac42b4b1eff211caed58e932394950d1d..b3349c8c4e362a8bf5f620ec2a7d74735486a3a6 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
@@ -221,7 +221,7 @@
 import Persist from '@/components/dialogs/Persist'
 import Citation from '@/components/identifier/Citation'
 import { formatTimestampUTCLabel, formatDateUTC } from '@/utils'
-import { findQuery, persistQuery } from '@/api/query'
+import QueryService from '@/api/query.service'
 
 export default {
   name: 'QueryShow',
@@ -402,54 +402,40 @@ export default {
       this.downloadLoading = false
       this.metadataLoading = false
     },
-    async downloadData () {
+    downloadData () {
       this.downloadLoading = true
-      try {
-        const config = this.config
-        config.headers.Accept = 'text/csv'
-        const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query/${this.$route.params.query_id}/export`, config)
-        console.debug('export query data', res)
-        const url = window.URL.createObjectURL(new Blob([res.data]))
-        const link = document.createElement('a')
-        link.href = url
-        link.setAttribute('download', 'subset.csv')
-        document.body.appendChild(link)
-        link.click()
-      } catch (err) {
-        console.error('Could not export query data', err)
-        this.$toast.error('Could not export query data')
-        this.error = true
-      }
-      this.downloadLoading = false
+      QueryService.export(this.$route.params.container_id, this.$route.params.database_id, this.$route.params.query_id)
+        .then((data) => {
+          const url = window.URL.createObjectURL(new Blob([data]))
+          const link = document.createElement('a')
+          link.href = url
+          link.setAttribute('download', 'subset.csv')
+          document.body.appendChild(link)
+          link.click()
+        })
+        .finally(() => {
+          this.downloadLoading = false
+        })
     },
-    async loadQuery () {
+    loadQuery () {
       this.loadingQuery = true
-      try {
-        const res = await findQuery(this.token, this.$route.params.container_id, this.$route.params.database_id, this.$route.params.query_id)
-        console.info('load query', res.data)
-        this.query = res.data
-      } catch (err) {
-        const { statusText, status } = err.response
-        if (status !== 401 && status !== 405) {
-          console.error('Failed to load query with status', status, 'and message', statusText)
-          this.$toast.error('Failed to load query: ' + statusText)
-        }
-        this.error = true
-      }
-      this.loadingQuery = false
+      QueryService.findOne(this.$route.params.container_id, this.$route.params.database_id, this.$route.params.query_id)
+        .then((query) => {
+          this.query = query
+        })
+        .finally(() => {
+          this.loadingQuery = false
+        })
     },
-    async save () {
+    save () {
       this.loadingSave = true
-      try {
-        const res = await persistQuery(this.token, this.$route.params.container_id, this.$route.params.database_id, this.$route.params.query_id)
-        console.info('persisted query', res.data)
-        this.query = res.data
-      } catch (error) {
-        console.error('Failed to persisted query', error)
-        this.$toast.error('Failed to persisted query')
-        this.error = true
-      }
-      this.loadingSave = false
+      QueryService.persist(this.$route.params.container_id, this.$route.params.database_id, this.$route.params.query_id)
+        .then((query) => {
+          this.query = query
+        })
+        .finally(() => {
+          this.loadingSave = false
+        })
     },
     openDialog () {
       this.persistQueryDialog = true
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/settings.vue b/fda-ui/pages/container/_container_id/database/_database_id/settings.vue
index 7a69a85091e52b6c460be216522c3064b0c29976..28cf44a2158a2bbf6cc6c25691ce528d2e5728a4 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/settings.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/settings.vue
@@ -15,7 +15,9 @@
             </template>
             <template v-slot:item.action="{ item }">
               <v-btn
+                v-if="item.user.username !== user.username"
                 x-small
+                :disabled="!canModifyAccess"
                 @click="modifyAccess(item)">
                 Modify
               </v-btn>
@@ -24,6 +26,7 @@
           <v-card-text>
             <v-btn
               small
+              :disabled="!canCreateAccess"
               color="warning"
               class="black--text"
               @click="giveAccess">
@@ -85,7 +88,7 @@
     <v-dialog
       v-model="editAccessDialog"
       max-width="640">
-      <EditAccess :username="username" @close-dialog="closeDialog" />
+      <EditAccess :username="username" :access-type="accessType" @close-dialog="closeDialog" />
     </v-dialog>
   </div>
 </template>
@@ -93,7 +96,8 @@
 <script>
 import DBToolbar from '@/components/DBToolbar'
 import EditAccess from '@/components/dialogs/EditAccess'
-import { modifyVisibility, modifyOwnership } from '@/api/database'
+import DatabaseService from '@/api/database.service'
+import UserService from '@/api/user.service'
 
 export default {
   components: {
@@ -105,6 +109,7 @@ export default {
       dialogDelete: false,
       confirm: null,
       username: null,
+      accessType: null,
       users: [],
       loading: false,
       loadingUsers: false,
@@ -183,6 +188,18 @@ export default {
         return false
       }
       return this.roles.includes('modify-database-owner')
+    },
+    canModifyAccess () {
+      if (!this.isOwner) {
+        return false
+      }
+      return this.roles.includes('update-database-access')
+    },
+    canCreateAccess () {
+      if (!this.isOwner) {
+        return false
+      }
+      return this.roles.includes('create-database-access')
     }
   },
   watch: {
@@ -204,70 +221,53 @@ export default {
   },
   methods: {
     closeDialog (event) {
-      if (event.success) {
-        this.loadDatabase()
-      }
-      this.loadDatabase()
+      this.reloadDatabase()
       this.editAccessDialog = false
     },
-    async updateDatabaseVisibility () {
-      try {
-        this.loading = true
-        await modifyVisibility(this.token, this.$route.params.container_id, this.$route.params.database_id, this.modifyVisibility.is_public)
-        this.$toast.success('Successfully updated the database visibility')
-        location.reload()
-      } catch (error) {
-        console.error('Failed to update database visibility', error)
-        this.$toast.error('Failed to update database visibility')
-      }
-      this.loading = false
+    updateDatabaseVisibility () {
+      this.loading = true
+      DatabaseService.modifyVisibility(this.$route.params.container_id, this.$route.params.database_id, this.modifyVisibility.is_public)
+        .then(() => {
+          this.$toast.success('Successfully updated the database visibility')
+          location.reload()
+        })
+        .finally(() => {
+          this.loading = false
+        })
     },
-    async updateDatabaseOwner () {
-      try {
-        this.loading = true
-        await modifyOwnership(this.token, this.$route.params.container_id, this.$route.params.database_id, this.modifyOwner.username)
-        this.$toast.success('Successfully updated the database owner')
-      } catch (error) {
-        console.error('Failed to update database owner', error)
-        this.$toast.error('Failed to update database owner')
-      }
-      this.loading = false
+    updateDatabaseOwner () {
+      this.loading = true
+      DatabaseService.modifyOwner(this.$route.params.container_id, this.$route.params.database_id, this.modifyOwner.username)
+        .then(() => {
+          this.$toast.success('Successfully updated the database owner')
+          location.reload()
+        })
+        .finally(() => {
+          this.loading = false
+        })
     },
     giveAccess () {
       this.username = null
+      this.accessType = null
       this.editAccessDialog = true
     },
     modifyAccess (item) {
       this.username = item.user.username
+      this.accessType = item.type
       this.editAccessDialog = true
     },
-    async loadUsers () {
+    loadUsers () {
       this.loadingUsers = true
-      try {
-        const res = await this.$axios.get('/api/user', this.config)
-        this.users = res.data
-        console.debug('users', this.users)
-      } catch (error) {
-        console.error('Failed to load users', error)
-        const { message } = error.response.data
-        this.$toast.error(`Failed to load users: ${message}`)
-      }
-      this.loadingUsers = false
+      UserService.findAll()
+        .then((users) => {
+          this.users = users
+        })
+        .finally(() => {
+          this.loadingUsers = false
+        })
     },
-    async loadDatabase () {
-      if (!this.$route.params.container_id || !this.$route.params.database_id) {
-        return
-      }
-      try {
-        this.loading = true
-        const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}`, this.config)
-        this.$store.commit('SET_DATABASE', res.data)
-        console.debug('database', this.database)
-      } catch (err) {
-        console.error('Could not load database', err)
-        this.$toast.error('Could not load database')
-      }
-      this.loading = false
+    reloadDatabase () {
+      this.$store.dispatch('reloadDatabase')
     }
   }
 }
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue
index 72022b57c94af3625d59739cbba55c117b764262..3f2e2818c750cbbb587c758f4e19ec2a371736bc 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue
@@ -72,6 +72,7 @@
 </template>
 <script>
 import TableToolbar from '@/components/TableToolbar'
+import TableService from '@/api/table.service'
 
 export default {
   components: {
@@ -196,24 +197,22 @@ export default {
       const { success } = event
       console.debug('closed dialog', event)
       if (success) {
-        this.loadTable()
+        this.$store.dispatch('reloadTable')
       }
       this.dialogSemantic = false
     },
-    async loadTable () {
+    loadTable () {
       if (!this.$route.params.container_id || !this.$route.params.database_id || !this.$route.params.table_id) {
         return
       }
-      try {
-        this.loading = true
-        const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}`, this.config)
-        this.$store.commit('SET_TABLE', res.data)
-        console.debug('table', this.table)
-      } catch (err) {
-        console.error('Could not load table', err)
-        this.$toast.error('Could not load table')
-      }
-      this.loading = false
+      this.loading = true
+      TableService.findOne(this.$route.params.container_id, this.$route.params.database_id, this.$route.params.table_id)
+        .then((table) => {
+          this.$store.commit('SET_TABLE', table)
+        })
+        .finally(() => {
+          this.loading = false
+        })
     }
   }
 }
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/create.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/create.vue
index 49fd24d9d8cc26ede48cfe6b1277d38b93465c93..e85a9d20187075bf6fce24bf001da095fe8075d7 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/table/create.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/table/create.vue
@@ -61,8 +61,7 @@
 <script>
 import TableSchema from '@/components/TableSchema'
 import { notEmpty } from '@/utils'
-import { createTable } from '@/api/table'
-import { findDatabase } from '@/api/database'
+import TableService from '@/api/table.service'
 
 export default {
   components: {
@@ -152,24 +151,14 @@ export default {
     submit () {
       this.$refs.form.validate()
     },
-    async createTable () {
-      try {
-        this.loading = true
-        const res = await createTable(this.token, this.$route.params.container_id, this.$route.params.database_id, this.tableCreate)
-        if (res.status === 201) {
-          this.error = false
+    createTable () {
+      this.loading = true
+      TableService.create(this.$route.params.container_id, this.$route.params.database_id, this.tableCreate)
+        .then(async (table) => {
           this.$toast.success('Table created')
-          await this.loadDatabase()
-          await this.$router.push(`/container/${this.$route.params.container_id}/database/${this.databaseId}/table/${res.data.id}`)
-        } else {
-          this.error = true
-          this.$toast.error(`Could not create table: status ${res.status}`)
-        }
-      } catch (err) {
-        this.error = true
-        console.error('could not create table', err)
-        this.$toast.error('Could not create table')
-      }
+          await this.$store.dispatch('reloadDatabase')
+          await this.$router.push(`/container/${this.$route.params.container_id}/database/${this.databaseId}/table/${table.id}`)
+        })
     },
     schemaClose (event) {
       console.debug('schema closed', event)
@@ -178,21 +167,6 @@ export default {
         return
       }
       this.createTable()
-    },
-    async loadDatabase () {
-      if (!this.$route.params.container_id || !this.$route.params.database_id) {
-        return
-      }
-      try {
-        this.loading = true
-        const res = await findDatabase(this.token, this.$route.params.container_id, this.$route.params.database_id)
-        this.$store.commit('SET_DATABASE', res.data)
-        console.debug('database', this.database)
-      } catch (error) {
-        console.error('Could not load database', error)
-        this.$toast.error('Could not load database')
-      }
-      this.loading = false
     }
   }
 }
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue
index 37d0ad3816f0492cb211387bae0be5a123c40d51..4c259e20b0458fc8b9aae167332688b324435a9d 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue
@@ -188,7 +188,7 @@
 import TableSchema from '@/components/TableSchema'
 import { notEmpty, isNonNegativeInteger, isResearcher } from '@/utils'
 import ContainerService from '@/api/container.service'
-import { listTables, createTable, dataImport } from '@/api/table'
+import TableService from '@/api/table.service'
 import { determineDataTypes } from '@/api/analyse'
 
 export default {
@@ -354,18 +354,15 @@ export default {
       }
       this.loading = false
     },
-    async listTables () {
-      try {
-        this.loading = true
-        const res = await listTables(this.token, this.$route.params.container_id, this.$route.params.database_id)
-        console.debug('tables', res.data)
-        this.tableNames = res.data.map(t => t.internal_name)
-      } catch (error) {
-        this.error = true
-        console.error('Failed to list tables', error)
-        this.$toast.error('Failed to list tables')
-      }
-      this.loading = false
+    listTables () {
+      this.loading = true
+      TableService.findAll(this.$route.params.container_id, this.$route.params.database_id)
+        .then((tables) => {
+          this.tableNames = tables.map(t => t.internal_name)
+        })
+        .finally(() => {
+          this.loading = false
+        })
     },
     schemaClose (event) {
       console.debug('schema closed', event)
@@ -385,7 +382,7 @@ export default {
       this.dateFormats = await ContainerService.findOne(this.$route.params.container_id).image.date_formats
       this.loading = true
     },
-    async createTable () {
+    createTable () {
       /* make enum values to array */
       const validColumns = this.tableCreate.columns.map((column) => {
         // validate `id` column: must be a PK
@@ -405,36 +402,21 @@ export default {
       // bail out if there is a problem with one of the columns
       if (!validColumns.every(Boolean)) { return }
 
-      let createResult
-      try {
-        this.loading = true
-        createResult = await createTable(this.token, this.$route.params.container_id, this.$route.params.database_id, this.tableCreate)
-        this.newTableId = createResult.data.id
-        console.debug('created table', createResult.data)
-      } catch (err) {
-        this.loading = false
-        this.error = true
-        if (err.response.status === 409) {
-          this.$toast.error('Table name already exists')
-        } else {
-          this.$toast.error('Could not create table')
-        }
-        console.error('create table failed', err)
-        return
-      }
-      let insertResult
-      try {
-        insertResult = await dataImport(this.token, this.$route.params.container_id, this.$route.params.database_id, createResult.data.id, this.tableImport)
-        console.debug('inserted table', insertResult.data)
-      } catch (err) {
-        this.loading = false
-        this.error = true
-        console.error('insert table failed', err)
-        this.$toast.error('Could not insert csv into table')
-        return
-      }
-      this.loading = false
-      this.step = 5
+      TableService.create(this.$route.params.container_id, this.$route.params.database_id, this.tableCreate)
+        .then((table) => {
+          this.newTableId = table.id
+          TableService.importCsv(this.$route.params.container_id, this.$route.params.database_id, table.id, this.tableImport)
+            .then(() => {
+              this.$toast.success('Successfully created table from import!')
+              this.step = 5
+            })
+            .finally(() => {
+              this.loading = false
+            })
+        })
+        .catch(() => {
+          this.loading = false
+        })
     }
   }
 }
diff --git a/fda-ui/pages/container/index.vue b/fda-ui/pages/container/index.vue
index a77355ab5f2936e6030593dd40a1ebe5b1c53e3f..9e4eb1ffff64834a148762b382d457b47329a09c 100644
--- a/fda-ui/pages/container/index.vue
+++ b/fda-ui/pages/container/index.vue
@@ -25,7 +25,6 @@
 import { mdiDatabaseArrowRightOutline } from '@mdi/js'
 import CreateDB from '@/components/dialogs/CreateDB'
 import DatabaseList from '@/components/DatabaseList'
-import { tokenToRoles } from '@/api/user'
 
 export default {
   components: {
@@ -56,6 +55,9 @@ export default {
     user () {
       return this.$store.state.user
     },
+    roles () {
+      return this.$store.state.roles
+    },
     config () {
       if (this.token === null) {
         return {}
@@ -68,8 +70,7 @@ export default {
       if (!this.token) {
         return false
       }
-      const roles = tokenToRoles(this.token)
-      return roles.includes('create-container') && roles.includes('create-database')
+      return this.roles.includes('create-container') && this.roles.includes('create-database')
     }
   },
   methods: {
diff --git a/fda-ui/pages/login.vue b/fda-ui/pages/login.vue
index d77f7df45a85fe8363992d6964a2086f84eaf777..66351469bcc28af905037d164153f1b2d6b5e24c 100644
--- a/fda-ui/pages/login.vue
+++ b/fda-ui/pages/login.vue
@@ -59,6 +59,7 @@
 
 <script>
 import AuthenticationService from '@/api/authentication.service'
+import UserService from '@/api/user.service'
 import UserMapper from '@/api/user.mapper'
 export default {
   data () {
@@ -103,10 +104,13 @@ export default {
       this.loading = true
       AuthenticationService.authenticatePlain(this.username, this.password)
         .then(() => {
-          const themeDark = UserMapper.getThemeDark(this.user)
-          console.debug('theme_dark', themeDark)
-          this.$vuetify.theme.dark = themeDark
-          this.$router.push('/container')
+          const userId = UserMapper.tokenToUserId(this.token)
+          UserService.findOne(userId)
+            .then((user) => {
+              this.$store.commit('SET_USER', user)
+              this.$vuetify.theme.dark = UserMapper.getThemeDark(this.user)
+              this.$router.push('/container')
+            })
         })
         .catch(() => {
           this.loading = false
diff --git a/fda-ui/pages/user/authentication.vue b/fda-ui/pages/user/authentication.vue
index 0843233abfe277a94703ec14830f79f8a867109b..92af24111141ae469c878c4e6eb8df2132e550e2 100644
--- a/fda-ui/pages/user/authentication.vue
+++ b/fda-ui/pages/user/authentication.vue
@@ -51,7 +51,7 @@
 
 <script>
 import UserToolbar from '@/components/UserToolbar'
-import { updateUserPassword } from '@/api/user'
+import UserService from '@/api/user.service'
 
 export default {
   components: {
@@ -89,17 +89,16 @@ export default {
   methods: {
     submit () {
     },
-    async changePassword () {
-      try {
-        this.loadingUpdate = true
-        const res = await updateUserPassword(this.token, this.user.id, this.password)
-        console.debug('password', res.data)
-        this.$toast.success('Successfully changed the password')
-      } catch (error) {
-        console.error('Failed to update password', error)
-        this.$toast.error('Failed to update password')
-      }
-      this.loadingUpdate = false
+    changePassword () {
+      this.loadingUpdate = true
+      UserService.updatePassword(this.user.id, this.password)
+        .then(() => {
+          this.$toast.success('Successfully changed the password')
+          this.loadingUpdate = false
+        })
+        .catch(() => {
+          this.loadingUpdate = false
+        })
     }
   }
 }
diff --git a/fda-ui/pages/user/info.vue b/fda-ui/pages/user/info.vue
index 104c4216d1dca4a7728f8f966c0611b61005c932..7ade357f0a6578ce8c7e682521ffb5454fc880b7 100644
--- a/fda-ui/pages/user/info.vue
+++ b/fda-ui/pages/user/info.vue
@@ -3,7 +3,7 @@
     <UserToolbar />
     <v-tabs-items v-model="tab">
       <v-tab-item>
-        <div v-if="canModifyInformation">
+        <div>
           <v-card flat>
             <v-card-title>User Information</v-card-title>
             <v-card-text>
@@ -26,24 +26,42 @@
                   <v-col md="6">
                     <v-text-field
                       v-model="model.firstname"
-                      :rules="[v => !!v || $t('Required')]"
-                      required
-                      label="Firstname *" />
+                      :disabled="!canModifyInformation"
+                      label="Firstname" />
                   </v-col>
                 </v-row>
                 <v-row dense>
                   <v-col md="6">
                     <v-text-field
                       v-model="model.lastname"
-                      :rules="[v => !!v || $t('Required')]"
-                      required
-                      label="Lastname *" />
+                      :disabled="!canModifyInformation"
+                      label="Lastname" />
+                  </v-col>
+                </v-row>
+                <v-row dense>
+                  <v-col md="6">
+                    <v-text-field
+                      v-model="model.affiliation"
+                      :disabled="!canModifyInformation"
+                      hint="e.g. University of xyz"
+                      label="Affiliation" />
+                  </v-col>
+                </v-row>
+                <v-row dense>
+                  <v-col md="6">
+                    <v-text-field
+                      v-model="model.orcid"
+                      :disabled="!canModifyInformation"
+                      maxlength="19"
+                      hint="e.g. 0000-0002-1825-0097"
+                      label="ORCID" />
                   </v-col>
                 </v-row>
                 <v-row>
                   <v-col>
                     <v-btn
                       small
+                      :disabled="!canModifyInformation"
                       color="primary"
                       :loading="loading"
                       @click="updateInfo">
@@ -51,25 +69,6 @@
                     </v-btn>
                   </v-col>
                 </v-row>
-                <!--              <v-row dense>-->
-                <!--                <v-col md="6">-->
-                <!--                  <v-text-field-->
-                <!--                    v-model="model.affiliation"-->
-                <!--                    disabled-->
-                <!--                    hint="e.g. University of xyz"-->
-                <!--                    label="Affiliation" />-->
-                <!--                </v-col>-->
-                <!--              </v-row>-->
-                <!--              <v-row dense>-->
-                <!--                <v-col md="6">-->
-                <!--                  <v-text-field-->
-                <!--                    v-model="model.orcid"-->
-                <!--                    disabled-->
-                <!--                    maxlength="19"-->
-                <!--                    hint="e.g. 0000-0002-1825-0097"-->
-                <!--                    label="ORCID" />-->
-                <!--                </v-col>-->
-                <!--              </v-row>-->
               </v-form>
             </v-card-text>
           </v-card>
@@ -99,7 +98,7 @@
 
 <script>
 import UserToolbar from '@/components/UserToolbar'
-import { tokenToRoles, updateUser, toggleUserTheme, getThemeDark, findUser } from '@/api/user'
+import UserService from '@/api/user.service'
 
 export default {
   components: {
@@ -130,7 +129,7 @@ export default {
       return this.$store.state.user
     },
     roles () {
-      return tokenToRoles(this.token)
+      return this.$store.state.roles
     },
     config () {
       if (this.token === null) {
@@ -150,86 +149,55 @@ export default {
       return this.roles.includes('modify-user-information')
     }
   },
-  watch: {
-    user () {
-      this.init()
-    }
-  },
   mounted () {
     this.init()
   },
   methods: {
     submit () {
     },
-    async updateInfo () {
-      try {
-        this.loadingUpdate = true
-        const payload = {
-          firstname: this.model.firstname,
-          lastname: this.model.lastname
-        }
-        const res = await updateUser(this.token, this.user.id, payload)
-        console.info('Updated user information')
-        const user = res.data
-        console.debug('user', user)
-        this.$store.commit('SET_USER', user)
-        this.error = false
-        this.$toast.success('Successfully updated user information')
-      } catch (error) {
-        console.error('update', error)
-        this.$toast.error('Failed to update user info')
-        this.error = true
+    updateInfo () {
+      this.loadingUpdate = true
+      const payload = {
+        firstname: this.model.firstname,
+        lastname: this.model.lastname,
+        orcid: this.model.orcid,
+        affiliation: this.model.affiliation
       }
-      this.loadingUpdate = false
+      UserService.updateInformation(this.user.id, payload)
+        .then(() => {
+          console.info('Updated user information')
+          this.$toast.success('Successfully updated user information')
+          this.reloadUser()
+        })
+        .finally(() => {
+          this.loadingUpdate = false
+        })
     },
-    async toggleTheme () {
-      try {
-        await toggleUserTheme(this.token, this.user.id, this.theme_dark)
-        await this.loadUser()
-        this.$vuetify.theme.dark = this.theme_dark
-      } catch (error) {
-        const { message } = error.response
-        console.error('Failed to update theme', error)
-        this.$toast.error('Failed to update theme: ' + message)
-        this.error = true
-      }
+    reloadUser () {
+      this.$store.dispatch('reloadUser')
     },
-    async loadUser () {
-      if (!this.token) {
-        return
-      }
-      try {
-        const res = await findUser(this.token)
-        const user = res.data
-        console.debug('user', user)
-        this.$store.commit('SET_USER', user)
-        const roles = tokenToRoles(this.token)
-        this.$store.commit('SET_ROLES', roles)
-        this.$vuetify.theme.dark = getThemeDark(user)
-        this.loading = false
-      } catch (error) {
-        console.error('Failed to load user', error)
-        const { status } = error.response
-        if (status === 401) {
-          console.error('Token expired', error)
-          this.$toast.warning('Login has expired')
-          this.logout()
-        } else {
-          console.error('user data', error)
-          this.$toast.error('Failed to load user')
-          this.error = true
-        }
-      }
+    toggleTheme () {
+      UserService.updateTheme(this.user.id, this.theme_dark)
+        .then(() => {
+          this.reloadUser()
+          this.$vuetify.theme.dark = this.theme_dark
+        })
     },
     init () {
       if (!this.user) {
+        console.warn('Object user is not yet available')
         return
       }
-      this.theme_dark = getThemeDark(this.user)
-      this.model.id = this.user.id
-      this.model.username = this.user.username
-      this.model.firstname = this.user.given_name
-      this.model.lastname = this.user.family_name
+      this.reloadUser()
+      this.theme_dark = this.user.attributes.theme_dark
+      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
+      }
     }
   }
 }
diff --git a/fda-ui/plugins/axios.js b/fda-ui/plugins/axios.js
index f627cf9093166194f6bbe47b51baba5a0d9360c6..5de5da3b202469b256c7ab811d438e21f170df42 100644
--- a/fda-ui/plugins/axios.js
+++ b/fda-ui/plugins/axios.js
@@ -25,7 +25,7 @@ api.interceptors.request.use((config) => {
         return config
       })
   }
-  console.debug('interceptor inject authorization header', exp)
+  console.debug('interceptor inject authorization header')
   config.headers.Authorization = `Bearer ${token}`
   return config
 })
diff --git a/fda-ui/store/index.js b/fda-ui/store/index.js
index 3de9499b7a4ecf8e0be4a51881e7a45a8b164d96..13f9e4e59be7936e970b9f272308195d785c9211 100644
--- a/fda-ui/store/index.js
+++ b/fda-ui/store/index.js
@@ -1,5 +1,8 @@
 import Vue from 'vue'
 import Vuex, { Store } from 'vuex'
+import UserService from '@/api/user.service'
+import DatabaseService from '@/api/database.service'
+import TableService from '@/api/table.service'
 
 Vue.use(Vuex)
 
@@ -25,28 +28,53 @@ const store = new Store({
   },
   mutations: {
     SET_TOKEN (state, token) {
+      console.debug('set state token', token)
       state.token = token
     },
     SET_REFRESH_TOKEN (state, refreshToken) {
+      console.debug('set state refreshToken', refreshToken)
       state.refreshToken = refreshToken
     },
     SET_ROLES (state, roles) {
+      console.debug('set state roles', roles)
       state.roles = roles
     },
     SET_USER (state, user) {
+      console.debug('set state user', user)
       state.user = user
     },
     SET_DATABASE (state, database) {
+      console.debug('set state database', database)
       state.database = database
     },
     SET_TABLE (state, table) {
+      console.debug('set state table', table)
       state.table = table
     },
     SET_ACCESS (state, access) {
+      console.debug('set state access', access)
       state.access = access
     }
   },
   actions: {
+    reloadUser ({ state, commit }) {
+      UserService.findOne(state.user.id)
+        .then((user) => {
+          commit('SET_USER', user)
+        })
+    },
+    reloadDatabase ({ state, commit }) {
+      DatabaseService.findOne(state.database.container.id, state.database.id)
+        .then((database) => {
+          commit('SET_DATABASE', database)
+        })
+    },
+    reloadTable ({ state, commit }) {
+      TableService.findOne(state.database.container.id, state.database.id, state.table.id)
+        .then((table) => {
+          commit('SET_TABLE', table)
+        })
+    }
   }
 })
 export default () => store
diff --git a/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java b/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java
index 2340c468874e170ba3edd68e0ae824751d20157e..5316b9e062ffae5a99c06d24bedc5c98f66599c3 100644
--- a/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java
+++ b/fda-user-service/rest-service/src/main/java/at/tuwien/endpoint/UserEndpoint.java
@@ -104,7 +104,7 @@ public class UserEndpoint {
     public ResponseEntity<UserDto> modify(@NotNull @PathVariable("id") String id,
                                           @NotNull @Valid @RequestBody UserUpdateDto data,
                                           @NotNull Principal principal)
-            throws UserNotFoundException, ForeignUserException {
+            throws UserNotFoundException, ForeignUserException, UserAttributeNotFoundException {
         log.debug("endpoint modify a user, id={}, data={}, principal={}", id, data, principal);
         final UserDto dto = userMapper.userToUserDto(userService.modify(id, data, principal));
         log.trace("modify user resulted in dto {}", dto);
@@ -120,7 +120,7 @@ public class UserEndpoint {
     public ResponseEntity<UserDto> theme(@NotNull @PathVariable("id") String id,
                                          @NotNull @Valid @RequestBody UserThemeSetDto data,
                                          @NotNull Principal principal)
-            throws UserNotFoundException, ForeignUserException {
+            throws UserNotFoundException, ForeignUserException, UserAttributeNotFoundException {
         log.debug("endpoint modify a user theme, id={}, data={}, principal={}", id, data, principal);
         final User user = userService.toggleTheme(id, data, principal);
         final UserDto dto = userMapper.userToUserDto(user);
diff --git a/fda-user-service/services/src/main/java/at/tuwien/exception/UserAttributeNotFoundException.java b/fda-user-service/services/src/main/java/at/tuwien/exception/UserAttributeNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0d3249868a20ff1211226b4fefd2eade255f3db
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/exception/UserAttributeNotFoundException.java
@@ -0,0 +1,21 @@
+package at.tuwien.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(code = HttpStatus.NOT_FOUND)
+public class UserAttributeNotFoundException extends Exception {
+
+    public UserAttributeNotFoundException(String msg) {
+        super(msg);
+    }
+
+    public UserAttributeNotFoundException(String msg, Throwable thr) {
+        super(msg, thr);
+    }
+
+    public UserAttributeNotFoundException(Throwable thr) {
+        super(thr);
+    }
+
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
index 1313e12b3b702a085222b5b77b52fdd228fb034f..e4fe5c286258089991df210c7099437c2670765b 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
@@ -6,6 +6,7 @@ import at.tuwien.api.user.UserBriefDto;
 import at.tuwien.api.user.UserDetailsDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.entities.user.User;
+import at.tuwien.entities.user.UserAttribute;
 import org.mapstruct.Mapper;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -29,4 +30,12 @@ public interface UserMapper {
         log.trace("mapped granted authority {} to granted authority {}", data, authority);
         return authority;
     }
+
+    default UserAttribute tripleToUserAttribute(String userId, String name, String value) {
+        return UserAttribute.builder()
+                .userId(userId)
+                .name(name)
+                .value(value)
+                .build();
+    }
 }
diff --git a/fda-user-service/services/src/main/java/at/tuwien/repository/jpa/UserAttributeRepository.java b/fda-user-service/services/src/main/java/at/tuwien/repository/jpa/UserAttributeRepository.java
index b3cf3ecedceee547dc556209959dad5cd6c4627f..08077e1525c52223220c166f6a8b4abc4f08270a 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/repository/jpa/UserAttributeRepository.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/repository/jpa/UserAttributeRepository.java
@@ -4,11 +4,14 @@ import at.tuwien.entities.user.UserAttribute;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
 import java.util.Optional;
 
 @Repository
 public interface UserAttributeRepository extends JpaRepository<UserAttribute, String> {
 
+    List<UserAttribute> findByUser(String userId);
+
     Optional<UserAttribute> findByUserIdAndName(String userId, String name);
 
 }
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/UserAttributeService.java b/fda-user-service/services/src/main/java/at/tuwien/service/UserAttributeService.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3471adb395d5c3a56fc8775c977340b48fecb69
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/UserAttributeService.java
@@ -0,0 +1,16 @@
+package at.tuwien.service;
+
+import at.tuwien.entities.user.UserAttribute;
+import at.tuwien.exception.UserAttributeNotFoundException;
+
+import java.util.List;
+
+public interface UserAttributeService {
+    List<UserAttribute> findAll(String userId);
+
+    UserAttribute find(String userId, String name) throws UserAttributeNotFoundException;
+
+    UserAttribute update(String userId, String name, String value) throws UserAttributeNotFoundException;
+
+    UserAttribute create(UserAttribute userAttribute);
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java b/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java
index fc4367b76898d55f332020fd19c75655913c0085..4f64b63e02c50d587ce298ce0f6743aa67444ed7 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/UserService.java
@@ -7,10 +7,7 @@ import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.entities.auth.Realm;
 import at.tuwien.entities.user.Role;
 import at.tuwien.entities.user.User;
-import at.tuwien.exception.ForeignUserException;
-import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.UserAlreadyExistsException;
-import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.exception.*;
 
 import java.security.Principal;
 import java.util.List;
@@ -38,12 +35,12 @@ public interface UserService {
     User create(SignupRequestDto data, Realm realm, Role role) throws RemoteUnavailableException, UserNotFoundException,
             UserAlreadyExistsException;
 
-    User modify(String id, UserUpdateDto data, Principal principal) throws UserNotFoundException, ForeignUserException;
+    User modify(String id, UserUpdateDto data, Principal principal) throws UserNotFoundException, ForeignUserException, UserAttributeNotFoundException;
 
     User updatePassword(String id, UserPasswordDto data, Principal principal) throws UserNotFoundException,
             ForeignUserException;
 
-    User toggleTheme(String id, UserThemeSetDto data, Principal principal) throws UserNotFoundException, ForeignUserException;
+    User toggleTheme(String id, UserThemeSetDto data, Principal principal) throws UserNotFoundException, ForeignUserException, UserAttributeNotFoundException;
 
     User find(String id) throws UserNotFoundException;
 }
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserAttributeServiceImpl.java b/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserAttributeServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6771f33a9cbfffef8377a0c931b74d248799a45b
--- /dev/null
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserAttributeServiceImpl.java
@@ -0,0 +1,51 @@
+package at.tuwien.service.impl;
+
+import at.tuwien.entities.user.UserAttribute;
+import at.tuwien.exception.UserAttributeNotFoundException;
+import at.tuwien.repository.jpa.UserAttributeRepository;
+import at.tuwien.service.UserAttributeService;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Log4j2
+@Service
+public class UserAttributeServiceImpl implements UserAttributeService {
+
+    private final UserAttributeRepository userAttributeRepository;
+
+    @Autowired
+    public UserAttributeServiceImpl(UserAttributeRepository userAttributeRepository) {
+        this.userAttributeRepository = userAttributeRepository;
+    }
+
+    @Override
+    public List<UserAttribute> findAll(String userId) {
+        return userAttributeRepository.findByUser(userId);
+    }
+
+    @Override
+    public UserAttribute find(String userId, String name) throws UserAttributeNotFoundException {
+        final Optional<UserAttribute> optional = userAttributeRepository.findByUserIdAndName(userId, name);
+        if (optional.isEmpty()) {
+            log.error("Failed to find user attribute with name {}", name);
+            throw new UserAttributeNotFoundException("Failed to find user attribute with name " + name);
+        }
+        return optional.get();
+    }
+
+    @Override
+    public UserAttribute update(String userId, String name, String value) throws UserAttributeNotFoundException {
+        final UserAttribute entity = find(userId, name);
+        entity.setValue(value);
+        return userAttributeRepository.save(entity);
+    }
+
+    @Override
+    public UserAttribute create(UserAttribute userAttribute) {
+        return userAttributeRepository.save(userAttribute);
+    }
+}
diff --git a/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
index c3616f99e6814e1fc2b9160f53c1dfd280794cf9..569eb90a4f15d522a962371196ac534ae3372445 100644
--- a/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
+++ b/fda-user-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
@@ -6,15 +6,13 @@ import at.tuwien.api.user.UserThemeSetDto;
 import at.tuwien.api.user.UserUpdateDto;
 import at.tuwien.entities.auth.Realm;
 import at.tuwien.entities.user.*;
-import at.tuwien.exception.ForeignUserException;
-import at.tuwien.exception.RemoteUnavailableException;
-import at.tuwien.exception.UserAlreadyExistsException;
-import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.exception.*;
 import at.tuwien.mapper.UserMapper;
 import at.tuwien.repository.jpa.CredentialRepository;
 import at.tuwien.repository.jpa.RoleMappingRepository;
 import at.tuwien.repository.jpa.UserAttributeRepository;
 import at.tuwien.repository.jpa.UserRepository;
+import at.tuwien.service.UserAttributeService;
 import at.tuwien.service.UserService;
 import lombok.extern.log4j.Log4j2;
 import org.keycloak.common.util.Base64;
@@ -46,19 +44,19 @@ public class UserServiceImpl implements UserService {
 
     private final UserMapper userMapper;
     private final UserRepository userRepository;
+    private final UserAttributeService userAttributeService;
     private final CredentialRepository credentialRepository;
     private final RoleMappingRepository roleMappingRepository;
-    private final UserAttributeRepository userAttributeRepository;
 
     @Autowired
     public UserServiceImpl(UserMapper userMapper, UserRepository userRepository,
-                           CredentialRepository credentialRepository, RoleMappingRepository roleMappingRepository,
-                           UserAttributeRepository userAttributeRepository) {
+                           UserAttributeService userAttributeService, CredentialRepository credentialRepository,
+                           RoleMappingRepository roleMappingRepository) {
         this.userMapper = userMapper;
         this.userRepository = userRepository;
+        this.userAttributeService = userAttributeService;
         this.credentialRepository = credentialRepository;
         this.roleMappingRepository = roleMappingRepository;
-        this.userAttributeRepository = userAttributeRepository;
     }
 
     @Override
@@ -121,16 +119,16 @@ public class UserServiceImpl implements UserService {
         user.setRealmId(realm.getId());
         user.setCreatedTimestamp(Instant.now().toEpochMilli());
         user = userRepository.save(user);
-        UserAttribute userAttribute = UserAttribute.builder()
-                .userId(user.getId())
-                .name("theme_dark")
-                .value("false")
-                .build();
-        userAttribute = userAttributeRepository.save(userAttribute);
+        final UserAttribute userAttribute1 = userAttributeService.create(userMapper.tripleToUserAttribute(user.getId(),
+                "theme_dark", "false"));
+        final UserAttribute userAttribute2 = userAttributeService.create(userMapper.tripleToUserAttribute(user.getId(),
+                "orcid", ""));
+        final UserAttribute userAttribute3 = userAttributeService.create(userMapper.tripleToUserAttribute(user.getId(),
+                "affiliation", ""));
         credential.setUserId(user.getId());
         credential = credentialRepository.save(credential);
         user.setCredentials(List.of(credential));
-        user.setAttributes(List.of(userAttribute));
+        user.setAttributes(List.of(userAttribute1, userAttribute2, userAttribute3));
         final RoleMapping tmp2 = RoleMapping.builder()
                 .userId(user.getId())
                 .roleId(role.getId())
@@ -144,7 +142,7 @@ public class UserServiceImpl implements UserService {
 
     @Override
     public User modify(String id, UserUpdateDto data, Principal principal) throws UserNotFoundException,
-            ForeignUserException {
+            ForeignUserException, UserAttributeNotFoundException {
         /* check */
         User user = findById(id);
         if (!user.getUsername().equals(principal.getName())) {
@@ -153,9 +151,12 @@ public class UserServiceImpl implements UserService {
         }
         user.setFirstname(data.getFirstname());
         user.setLastname(data.getLastname());
-        /* save */
+        /* save in metadata database */
         user = userRepository.save(user);
         log.info("Modified user with id {}", user.getId());
+        /* modify attributes */
+        userAttributeService.update(user.getId(), "orcid", data.getOrcid());
+        userAttributeService.update(user.getId(), "affiliation", data.getAffiliation());
         return user;
     }
 
@@ -191,28 +192,15 @@ public class UserServiceImpl implements UserService {
 
     @Override
     public User toggleTheme(String id, UserThemeSetDto data, Principal principal) throws UserNotFoundException,
-            ForeignUserException {
+            ForeignUserException, UserAttributeNotFoundException {
         /* check */
         final User user = findById(id);
         if (!user.getUsername().equals(principal.getName())) {
             log.error("Failed to modify user: attempting to modify other user");
             throw new ForeignUserException("Failed to modify user: attempting to modify other user");
         }
-        final Optional<UserAttribute> optional = userAttributeRepository.findByUserIdAndName(user.getId(), "theme_dark");
-        if (optional.isEmpty()) {
-            final UserAttribute theme = UserAttribute.builder()
-                    .user(user)
-                    .value(data.getThemeDark().toString())
-                    .build();
-            final UserAttribute attribute = userAttributeRepository.save(theme);
-            log.info("Updated theme by creating attribute with id {}", attribute);
-            return user;
-        }
-        final UserAttribute theme = optional.get();
-        theme.setValue(data.getThemeDark().toString());
-        final UserAttribute attribute = userAttributeRepository.save(theme);
-        user.setAttributes(List.of(attribute));
-        log.info("Updated theme by updating attribute with id {}", attribute);
+        final UserAttribute entity = userAttributeService.update(user.getId(), "theme_dark", data.getThemeDark().toString());
+        log.info("Updated theme by updating attribute with id {}", entity.getId());
         return user;
     }