diff --git a/caosdb-proto b/caosdb-proto
index 533c8e7341d0659e3cc43d834793a7a965703f55..c6405e538c179d2a8af952f85d9e9dc51fbadb92 160000
--- a/caosdb-proto
+++ b/caosdb-proto
@@ -1 +1 @@
-Subproject commit 533c8e7341d0659e3cc43d834793a7a965703f55
+Subproject commit c6405e538c179d2a8af952f85d9e9dc51fbadb92
diff --git a/src/EntityACL.js b/src/EntityACL.js
new file mode 100644
index 0000000000000000000000000000000000000000..fc4eb782ffe27e21a4822178e46cdcb554465c22
--- /dev/null
+++ b/src/EntityACL.js
@@ -0,0 +1,328 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+import {
+    api
+} from "./EntityApi";
+
+
+export class EntityACI {
+    constructor({
+        role,
+        grant,
+        priority,
+        permissions,
+        capabilities
+    }) {
+        this.role = role;
+        this.grant = grant;
+        this.priority = priority;
+        this.permissions = permissions || {
+            retrieve_entity: false,
+            retrieve_acl: false,
+            retrieve_history: false,
+            retrieve_owner: false,
+            retrieve_file: false,
+            delete_entity: false,
+            edit_acl: false,
+            update_description: false,
+            update_value: false,
+            update_role: false,
+            update_remove_parent: false,
+            update_add_parent: false,
+            update_remove_property: false,
+            update_add_property: false,
+            update_name: false,
+            update_data_type: false,
+            update_query_template_definition: false,
+            update_remove_file: false,
+            update_add_file: false,
+            update_move_file: false,
+            use_as_reference: false,
+            use_as_property: false,
+            use_as_parent: false,
+            use_as_data_type: false,
+        }
+        this.capabilities = capabilities || {
+            delete_aci: false,
+        }
+    }
+
+    isEditAcl() {
+        return this.permissions.edit_acl;
+    }
+
+    setEditAcl(val) {
+        val = typeof val === "undefined" ? true : val;
+        this.permissions.edit_acl = val;
+    }
+
+    isDelete() {
+        return this.permissions.delete_entity;
+    }
+
+    setDelete(val) {
+        val = typeof val === "undefined" ? true : val;
+        this.permissions.delete_entity = val;
+    }
+
+    isFullRetrieve() {
+        return this.permissions.retrieve_entity &&
+            this.permissions.retrieve_acl &&
+            this.permissions.retrieve_history &&
+            this.permissions.retrieve_owner &&
+            this.permissions.retrieve_file;
+    }
+
+    setFullRetrieve(val) {
+        val = typeof val === "undefined" ? true : val;
+        this.permissions.retrieve_entity = val;
+        this.permissions.retrieve_acl = val;
+        this.permissions.retrieve_history = val;
+        this.permissions.retrieve_owner = val;
+        this.permissions.retrieve_file = val;
+    }
+
+    isPartialRetrieve() {
+        return this.permissions.retrieve_entity ||
+            this.permissions.retrieve_acl ||
+            this.permissions.retrieve_history ||
+            this.permissions.retrieve_owner ||
+            this.permissions.retrieve_file;
+    }
+
+    isFullUse() {
+        return this.permissions.use_as_reference &&
+            this.permissions.use_as_property &&
+            this.permissions.use_as_parent &&
+            this.permissions.use_as_data_type;
+    }
+
+    setFullUse(val) {
+        val = typeof val === "undefined" ? true : val;
+        this.permissions.use_as_reference = val;
+        this.permissions.use_as_property = val;
+        this.permissions.use_as_parent = val;
+        this.permissions.use_as_data_type = val;
+    }
+
+    isPartialUse() {
+        return this.permissions.use_as_reference ||
+            this.permissions.use_as_property ||
+            this.permissions.use_as_parent ||
+            this.permissions.use_as_data_type;
+    }
+
+    isFullUpdate() {
+        return this.permissions.update_description &&
+            this.permissions.update_value &&
+            this.permissions.update_role &&
+            this.permissions.update_remove_parent &&
+            this.permissions.update_add_parent &&
+            this.permissions.update_remove_property &&
+            this.permissions.update_add_property &&
+            this.permissions.update_name &&
+            this.permissions.update_data_type &&
+            this.permissions.update_query_template_definition &&
+            this.permissions.update_remove_file &&
+            this.permissions.update_add_file &&
+            this.permissions.update_move_file;
+    }
+
+    setFullUpdate(val) {
+        val = typeof val === "undefined" ? true : val;
+        this.permissions.update_description = val;
+        this.permissions.update_value = val;
+        this.permissions.update_role = val;
+        this.permissions.update_remove_parent = val;
+        this.permissions.update_add_parent = val;
+        this.permissions.update_remove_property = val;
+        this.permissions.update_add_property = val;
+        this.permissions.update_name = val;
+        this.permissions.update_data_type = val;
+        this.permissions.update_query_template_definition = val;
+        this.permissions.update_remove_file = val;
+        this.permissions.update_add_file = val;
+        this.permissions.update_move_file = val;
+    }
+
+    isPartialUpdate() {
+        return this.permissions.update_description ||
+            this.permissions.update_value ||
+            this.permissions.update_role ||
+            this.permissions.update_remove_parent ||
+            this.permissions.update_add_parent ||
+            this.permissions.update_remove_property ||
+            this.permissions.update_add_property ||
+            this.permissions.update_name ||
+            this.permissions.update_data_type ||
+            this.permissions.update_query_template_definition ||
+            this.permissions.update_remove_file ||
+            this.permissions.update_add_file ||
+            this.permissions.update_move_file;
+    }
+
+    impliesOwnership() {
+        return this.grant && !this.isOtherRole() && !this.isOwnerRole() && this.permissions.edit_acl;
+    }
+
+    isOtherRole() {
+        return this.role === "?OTHER?";
+    }
+
+    isOwnerRole() {
+        return this.role === "?OWNER?";
+    }
+}
+
+export class EntityACL {
+    constructor({
+        id,
+        acis,
+        current_permissions
+    }) {
+        this.id = id;
+        this.acis = acis || [];
+        this.current_permissions = current_permissions || {}
+    }
+
+    getOwners() {
+        return this.acis.filter(aci => aci.impliesOwnership()).map(aci => aci.role);
+    }
+
+}
+
+const mappingJsToProtoPermissions = {
+    "retrieve_entity": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_ENTITY,
+    "retrieve_acl": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_ACL,
+    "retrieve_history": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_HISTORY,
+    "retrieve_owner": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_OWNER,
+    "retrieve_file": api.v1.EntityPermission.ENTITY_PERMISSION_RETRIEVE_FILE,
+    "delete_entity": api.v1.EntityPermission.ENTITY_PERMISSION_DELETE,
+    "edit_acl": api.v1.EntityPermission.ENTITY_PERMISSION_EDIT_ACL,
+    "update_description": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_DESCRIPTION,
+    "update_value": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_VALUE,
+    "update_role": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ROLE,
+    "update_remove_parent": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_REMOVE_PARENT,
+    "update_add_parent": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ADD_PARENT,
+    "update_remove_property": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_REMOVE_PROPERTY,
+    "update_add_property": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ADD_PROPERTY,
+    "update_name": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_NAME,
+    "update_data_type": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_DATA_TYPE,
+    "update_query_template_definition": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_QUERY_TEMPLATE_DEFINITION,
+    "update_remove_file": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_REMOVE_FILE,
+    "update_add_file": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_ADD_FILE,
+    "update_move_file": api.v1.EntityPermission.ENTITY_PERMISSION_UPDATE_MOVE_FILE,
+    "use_as_reference": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_REFERENCE,
+    "use_as_property": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_PROPERTY,
+    "use_as_parent": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_PARENT,
+    "use_as_data_type": api.v1.EntityPermission.ENTITY_PERMISSION_USE_AS_DATA_TYPE,
+}
+
+// produces the reversed dict from mappingJsToProtoPermissions
+const mappingProtoPermissionsToJs = (() => {
+    const result = {}
+    Object.keys(mappingJsToProtoPermissions).forEach(key => {
+        result[mappingJsToProtoPermissions[key]] = key;
+    });
+    return result;
+})();
+
+export function convertMessageToEntityPermissions(message) {
+    const permissions = {};
+    for (let p of message) {
+        permissions[mappingProtoPermissionsToJs[p]] = true;
+    }
+    return permissions;
+
+}
+
+export function convertMessageToEntityPermissionRuleCapabilities(message) {
+    const capabilities = {};
+    for (let c of message) {
+        if (c === api.v1.EntityPermissionRuleCapability.ENTITY_PERMISSION_RULE_CAPABILITY_DELETE) {
+            capabilities.delete_aci = true;
+        }
+    }
+    return capabilities;
+}
+
+export function convertMessageToEntityACI(message) {
+    const role = message.getRole();
+    const grant = message.getGrant();
+    const priority = message.getPriority();
+    const permissions = message.getPermissionsList();
+    const capabilities = message.getCapabilitiesList();
+    const aci = new EntityACI({
+        role: role,
+        grant: grant,
+        priority: priority
+    });
+    aci.permissions = convertMessageToEntityPermissions(permissions);
+    aci.capabilities = convertMessageToEntityPermissionRuleCapabilities(capabilities);
+    return aci;
+}
+
+export function convertMessageToEntityAclPermission(message) {
+    const permissions = {
+        "edit_acl": false,
+        "edit_priority_acl": false,
+    };
+
+    if (message === api.v1.EntityAclPermission.ENTITY_ACL_PERMISSION_EDIT_ACL) {
+        permissions.edit_acl = true;
+    } else if (message === api.v1.EntityAclPermission.ENTITY_ACL_PERMISSION_EDIT_PRIORITY_ACL) {
+        permissions.edit_acl = true;
+        permissions.edit_priority_acl = true;
+    }
+
+    return permissions;
+}
+
+export function convertMessageToEntityACL(message) {
+    const id = message.getId();
+    const acis = message.getRulesList();
+    const permission = message.getPermission();
+    return new EntityACL({
+        id: id,
+        acis: acis.map(convertMessageToEntityACI),
+        current_permissions: convertMessageToEntityAclPermission(permission)
+    });
+}
+
+export function convertEntityAciToMessage(aci) {
+    const result = new api.v1.EntityPermissionRule();
+    result.setRole(aci.role);
+    result.setPriority(aci.priority);
+    result.setGrant(aci.grant);
+    result.setPermissionsList(Object.keys(aci.permissions)
+        .filter(key => aci.permissions[key] && mappingJsToProtoPermissions[key])
+        .map(key => {
+            return mappingJsToProtoPermissions[key];
+        }));
+    return result;
+}
+
+export function convertEntityAclToMessage(acl) {
+    const result = new api.v1.EntityACL();
+    result.setId(acl.id);
+    result.setRulesList(acl.acis.map(convertEntityAciToMessage));
+    return result;
+}
diff --git a/src/TransactionService.js b/src/TransactionService.js
index 53e5cd5688e154cdf882557d0d654aa93c1f8c36..14533131a496ed83d48fb6b3a33953ad12733699 100644
--- a/src/TransactionService.js
+++ b/src/TransactionService.js
@@ -1,8 +1,9 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+ * Copyright (C) 2021-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021-2023 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+ * Copyright (C) 2021-2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify it under
  * the terms of the GNU Affero General Public License as published by the Free
@@ -20,6 +21,10 @@
 import {
     api
 } from "./EntityApi";
+import {
+    convertMessageToEntityACL,
+    convertEntityAclToMessage
+} from "./EntityACL"
 
 export class TransactionService {
 
@@ -84,4 +89,26 @@ export class TransactionService {
         const queryRequest = this._CreateQueryRequest(query);
         return new Promise(this._PrepareTransaction(queryRequest));
     }
+
+    async retrieveEntityAcl(id) {
+        const client = new api.v1.EntityTransactionServicePromiseClient(this.uri, null, null);
+        const request = new api.v1.MultiRetrieveEntityACLRequest();
+        request.addId(id);
+        const response = await client.multiRetrieveEntityACL(request, {});
+
+        return convertMessageToEntityACL(response.getAclsList()[0]);
+    }
+
+    async updateEntityAcl(acl) {
+        const updateAcl = convertEntityAclToMessage(acl);
+
+        const client = new api.v1.EntityTransactionServicePromiseClient(this.uri, null, null);
+        const request = new api.v1.MultiUpdateEntityACLRequest();
+        request.setAclsList([updateAcl]);
+
+        const response = await client.multiUpdateEntityACL(request, {});
+        return response;
+    }
+
+
 }
diff --git a/src/index.js b/src/index.js
index 3bf2d0d958637ce1a46eb8f4e26a3514e183ac0f..3c1a771dff5a234243d1dbc2774703e2d5ab48e8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -22,6 +22,12 @@ export {
 }
 from "./Entity";
 
+export {
+    EntityACI,
+    EntityACL
+}
+from "./EntityACL";
+
 export {
     Property
 }