diff --git a/docs/build/.pages b/docs/build/.pages
index c07c07c3d..c7f752244 100644
--- a/docs/build/.pages
+++ b/docs/build/.pages
@@ -22,3 +22,4 @@ nav:
- Evaluate Template Operator: evaluate-template
- Build Knowledge Graphs from Kafka Topics: kafka-consumer
- Spark: spark
+ - Project Access Control: project-access-control
diff --git a/docs/build/index.md b/docs/build/index.md
index ef390a2a7..ea385eedb 100644
--- a/docs/build/index.md
+++ b/docs/build/index.md
@@ -24,6 +24,7 @@ The Build stage turns your source data—across files, databases, APIs, and stre
- [Cool IRIs](cool-iris/index.md) --- URIs and IRIs are character strings identifying the nodes and edges in the graph. Defining them is an important step in creating an exploitable Knowledge Graph for your Company.
- [Define Prefixes / Namespaces](define-prefixes-namespaces/index.md) --- Namespace declarations allow for abbreviation of IRIs by using a prefixed name instead of an IRI, in particular when writing SPARQL queries or Turtle.
- [Spark](spark/index.md) --- Explainer of Apache Spark and its integration within the BUILD platform.
+ - [Project Access Control](project-access-control/index.md) --- Restrict a project to the members of selected user groups.
- :material-list-status: Tutorials
diff --git a/docs/build/project-access-control/index.md b/docs/build/project-access-control/index.md
new file mode 100644
index 000000000..f60c2c677
--- /dev/null
+++ b/docs/build/project-access-control/index.md
@@ -0,0 +1,85 @@
+---
+icon: material/lock-outline
+tags:
+ - Security
+ - Project
+---
+# Project access control
+
+## Introduction
+
+In eccenca Corporate Memory, project access control restricts a Build project to the members of selected user groups.
+Users who are not a member of one of these groups do not see the project and cannot open it.
+
+!!! info "Project access control is disabled by default"
+
+ An administrator enables project access control in the Build configuration, see [Project access control](../../deploy-and-configure/configuration/dataintegration/index.md#project-access-control).
+ While it is disabled, the **Access control** section and the **Groups** field described on this page are not shown.
+
+## Who can access a project
+
+The groups assigned to a project determine who can access it:
+
+- A project without groups is accessible to all users.
+- A project with groups is accessible to every user who is a member of at least one of these groups.
+- Administrators can access all projects, regardless of the assigned groups.
+
+Administrators are the accounts that hold the admin action of the Build configuration, see [Administrators](../../deploy-and-configure/configuration/dataintegration/index.md#administrators).
+
+Access is not divided into read access and write access.
+A user who can access a project can use it without restrictions, which includes changing its groups.
+
+A project that a user cannot access is not listed in the workspace.
+Opening a link to such a project shows an error message instead of the project.
+
+## View the groups of a project
+
+Open the project.
+The **Access control** section shows the assigned groups under **Groups**.
+If no groups are assigned, the section shows the message "No groups configured. This project is visible to all users." instead.
+
+## Restrict a project to groups
+
+1. Open the project.
+2. In the **Access control** section, click :eccenca-item-edit: **Edit access control**.
+3. Select one or more groups in the **Groups** field.
+4. Click **Save**.
+
+The **Groups** field marks each group that the current user is a member of with "(member)".
+For administrators, the groups are not marked.
+
+To make the project accessible to all users again, remove all groups from the **Groups** field and click **Save**.
+
+### Add a group that is not listed
+
+The list of groups in the **Groups** field can be incomplete.
+To assign a group that is not listed, enter its name in the **Groups** field and select **Add custom group**.
+
+The name must match the name of the group exactly, including capitalization.
+A misspelled group matches no user, so a warning lists the custom groups for review before saving.
+
+### Avoid losing access
+
+A warning appears when a group is added that the current user is not a member of.
+After saving, the current user keeps access only if at least one of the selected groups is a group of this user.
+Administrators do not see this warning, because they keep access to all projects.
+
+!!! warning "Loss of access"
+
+ A user who is not a member of any assigned group can no longer open the project or change its groups.
+ Only a member of one of the assigned groups or an administrator can restore the access.
+
+## Groups of new projects
+
+The **Groups** field is also part of the dialogs that create, clone, and import a project:
+
+- When a project is created, the field is empty, so the project is accessible to all users unless groups are selected.
+- When a project is cloned, the field is prefilled with the groups of the original project that the current user is a member of.
+- When a project is imported, the field is empty.
+ If the import replaces an existing project, the field is not shown and the project keeps its groups.
+
+!!! warning "Groups are not part of a project export"
+
+ By default, a project export does not contain the groups of the project.
+ Select the groups again when importing a restricted project.
+ Otherwise, the imported project is accessible to all users.
diff --git a/docs/deploy-and-configure/configuration/access-conditions/index.md b/docs/deploy-and-configure/configuration/access-conditions/index.md
index 12b9f3ab4..24a80d1dc 100644
--- a/docs/deploy-and-configure/configuration/access-conditions/index.md
+++ b/docs/deploy-and-configure/configuration/access-conditions/index.md
@@ -92,7 +92,7 @@ PREFIX :
| `:AllActions` | Represents all actions. You can use it to grant execution rights to all actions. |
| `:Build` | Represents the action needed to use eccenca Build (DataIntegration) component of eccenca Corporate Memory. |
| `:Build-AdminPython` | Represents the action needed to use eccenca Build (DataIntegration)'s Python plugin management component of eccenca Corporate Memory. |
-| `:Build-AdminWorkspace` | Represents the action needed to use eccenca Build (DataIntegration)'s workspace administration component of eccenca Corporate Memory. |
+| `:Build-AdminWorkspace` | Represents the action needed to use eccenca Build (DataIntegration)'s workspace administration component of eccenca Corporate Memory. If [project access control](../dataintegration/index.md#project-access-control) is enabled, this action also grants access to all projects, unless a different admin action is configured. |
| `:ChangeAccessConditions` | Represents the action needed to use the Authorization management API (see Developer Manual). You can use it as object of the `eccauth:allowedAction` property to grant access to the Authorization management API if the user fulfills the access condition. |
| `:Explore-BKE-Manage` | Represents the action needed to view, create, edit and delete visualisations in the BKE-Module (needs access to config graph as well). |
| `:Explore-BKE-Read` | Allows to use the BKE-Module interface in read-only mode (needs access to config graph as well). |
diff --git a/docs/deploy-and-configure/configuration/dataintegration/index.md b/docs/deploy-and-configure/configuration/dataintegration/index.md
index ac1a38748..a5f7821e1 100644
--- a/docs/deploy-and-configure/configuration/dataintegration/index.md
+++ b/docs/deploy-and-configure/configuration/dataintegration/index.md
@@ -618,6 +618,55 @@ provenance.graph = https://ns.eccenca.com/example/data/dataset/
provenance.persistWorkflowProvenancePlugin.plugin = rdfWorkflowProvenance
```
+## Project access control
+
+By default, every user who is allowed to use eccenca Build (DataIntegration) can access all projects.
+Project access control restricts individual projects to the members of selected user groups.
+It is disabled by default and is enabled with the following parameter:
+
+```conf
+workspace.accessControl.enabled = true
+```
+
+A project without assigned groups remains accessible to all users.
+The groups are assigned per project in the user interface, see [Project access control](../../../build/project-access-control/index.md).
+
+The following parameters are available:
+
+| Parameter | Type | Description | Default |
+|-|-|-|-|
+| workspace.accessControl.enabled | Boolean | Enables project access control. If disabled, all users can access all projects, regardless of the groups assigned to a project. | false |
+| workspace.accessControl.adminAction | String | The action that grants access to all projects, regardless of group membership. | |
+| workspace.accessControl.groupProvider.plugin | String | The plugin that provides the groups offered for selection in the user interface. | dpAccessControlGroupProvider |
+
+### Group membership
+
+The groups of a user are read from the `groups` claim of the OAuth access token.
+A user can access a restricted project if at least one of these groups is assigned to the project.
+Group names are compared exactly, including capitalization.
+
+In Keycloak, a **Group Membership** mapper adds the `groups` claim to the token, see [Access conditions, roles and groups](../keycloak/index.md#access-conditions-roles-and-groups).
+
+### Groups offered for selection
+
+The default group provider `dpAccessControlGroupProvider` requests the known groups from the eccenca Explore backend (DataPlatform).
+These are the groups of users who have already logged in and the groups that are used in access conditions.
+Only groups whose IRI starts with `http://eccenca.com/` are offered, and they are shown without this prefix.
+If the request fails, for example because the account is not allowed to manage access conditions, the groups that are already assigned to Build (DataIntegration) projects are offered instead.
+
+In addition, the selection always contains the groups of the current user and the groups already assigned to the project.
+The list can therefore be incomplete.
+A group that is not listed can be entered manually.
+
+### Administrators
+
+Accounts that hold the action configured in `workspace.accessControl.adminAction` can access and manage all projects, regardless of the assigned groups.
+By default, this is the `:Build-AdminWorkspace` action, see [Access Conditions](../access-conditions/index.md#define-what-grants-are-given).
+Accounts that are granted `:AllActions` hold this action as well.
+
+Grant this action to at least one account.
+Otherwise, a project whose groups no longer match any user cannot be opened or changed by anyone.
+
## Logging
Logging for eccenca Build (DataIntegration) is based on the [Logback](https://logback.qos.ch/) logging framework. There are two ways to change the logging behavior from the default, the first is to provide a logback.xml file, the second is to set various logging properties in the `dataintegration.conf` file.
diff --git a/nav.yml b/nav.yml
index 1b1ad751b..d0f380a00 100644
--- a/nav.yml
+++ b/nav.yml
@@ -482,6 +482,8 @@ nav:
- build/kafka-consumer/index.md
- Spark:
- build/spark/index.md
+ - Project Access Control:
+ - build/project-access-control/index.md
- Explore:
- Explore: explore-and-author/index.md
- Knowledge graphs: