diff --git a/docs/concepts/access-control.md b/docs/concepts/access-control.md
index 785f23b..c5f213e 100644
--- a/docs/concepts/access-control.md
+++ b/docs/concepts/access-control.md
@@ -2,8 +2,12 @@
Dependency-Track uses a role-based access control model built around **permissions**,
**teams**, and **users**. Permissions can be assigned to teams or directly to users.
-A user's effective permissions are the union of their direct permissions and the
-permissions of every team they belong to.
+
+!!! note "Effective permissions"
+
+ A user's effective permissions are the **union** of their direct permissions
+ and the permissions of every team they belong to. Permissions are never
+ intersected or downgraded by team membership.
## Users
@@ -18,23 +22,6 @@ Three types of users exist:
All user types share the same permission model. The authentication mechanism determines
how the system verifies a user's identity, not what they can access.
-### LDAP authentication flow
-
-With LDAP, Dependency-Track authenticates users by performing a service-account
-bind to locate the user's directory entry, then attempting a bind with the user's
-own credentials to verify their password. On success, the system grants access.
-With user provisioning turned on, Dependency-Track creates the account
-automatically on first login.
-
-### OIDC authentication flow
-
-With OIDC, the frontend redirects the user to the identity provider's authorization
-endpoint. After the user authenticates, the IdP returns an ID token to the frontend,
-which forwards it to the API server for validation. The API server verifies the token
-against the IdP's discovery endpoint and extracts the username from the configured
-claim. With user provisioning turned on, Dependency-Track creates accounts on
-first login.
-
## Teams
A team is a named collection of users and API keys. Teams hold permissions, which makes
@@ -52,20 +39,138 @@ API keys belong to a team and carry the same permissions as that team. They auth
automated access (CI/CD pipelines, integrations) without associating requests with a
specific human user.
+Deleting a team also deletes its API keys and any project access assignments
+made through it. Projects and user accounts are unaffected, but users lose the
+permissions they had inherited from the deleted team.
+
## Portfolio access control
-By default, all teams with `VIEW_PORTFOLIO` can see every project. Access Control Lists
-(ACLs) restrict portfolio visibility so that a team can only see the projects explicitly
-assigned to it.
+By default, every principal with `VIEW_PORTFOLIO` can see every project.
+Portfolio Access Control (PAC) restricts that visibility so a team can only act
+on the projects explicitly assigned to it. The per-project list of assigned
+teams is the project's Access Control List (ACL).
+
+With PAC enabled, ACL membership gates every operation on a project: viewing,
+BOM upload, editing, deletion, and vulnerability triage. The portfolio
+permissions (`VIEW_PORTFOLIO`, `PORTFOLIO_MANAGEMENT_UPDATE`, and so on) become
+*necessary but not sufficient*: a principal must hold the relevant permission
+**and** belong to a team on the project's ACL.
+
+Enable PAC in **Administration > Access Management > Portfolio Access Control**.
-Enable ACLs in **Administration > Access Management > Portfolio Access Control**.
-Once active, every project must be explicitly assigned to at least one team for it to
-be visible to non-administrator users.
+!!! warning "Enabling PAC affects existing projects"
-ACLs are most useful in multi-tenant scenarios where different teams should not see
-each other's projects. For single-team or open environments, ACLs add management
+ Existing projects keep their data but start with no team assignments. Until
+ an administrator (or a principal with `PORTFOLIO_ACCESS_CONTROL_BYPASS`)
+ assigns at least one team to each project, those projects become invisible
+ to all non-administrator users. Plan the assignment rollout before enabling
+ PAC on a production instance.
+
+PAC is most useful in multi-tenant scenarios where different teams should not see
+each other's projects. For single-team or open environments, PAC adds management
overhead without security benefit.
+### How PAC interacts with permissions
+
+Permissions and ACLs are orthogonal:
+
+* **Permissions** define *what a principal can do*, such as uploading BOMs,
+ editing projects, or triaging vulnerabilities. They are global to the
+ principal. The model has no per-project permissions.
+* **ACLs** define *which projects a principal can do it on*. They gate both reads
+ and writes, but do not change which capabilities the principal holds.
+
+To act on a project, a principal needs both the relevant permission *and* ACL
+access to that project. A user with `PORTFOLIO_MANAGEMENT_UPDATE` can edit every
+project they have ACL access to, and none of the ones they don't. Removing a
+team from a project's ACL revokes that team's access to the project but leaves
+the team's permissions unchanged elsewhere.
+
+### Pattern: separating permission teams from access teams
+
+Because permissions and ACLs compose independently, a useful pattern is to
+split teams by role:
+
+* **Permission teams** carry capabilities (`VIEW_PORTFOLIO`,
+ `VULNERABILITY_ANALYSIS`, and so on) but are not assigned to any project.
+* **Access teams** hold no permissions but are assigned to a subset of
+ projects.
+
+A user joins one team of each kind. Their effective rights are the union of
+all their teams' permissions, scoped to the union of all their teams' ACL
+grants. This emulates per-project permissions without the model having to
+support them directly.
+
+For an organization with a *Front Office* and a *Back Office* portfolio:
+
+```mermaid
+flowchart LR
+ Alice(["Alice
Developer, Front Office"])
+ Bob(["Bob
Developer, Back Office"])
+ Carol(["Carol
Auditor, Front + Back Office"])
+
+ subgraph Permission teams
+ Devs["Developers
VIEW_PORTFOLIO
VIEW_VULNERABILITY"]
+ Auditors["Auditors
VIEW_PORTFOLIO
VIEW_VULNERABILITY
VULNERABILITY_ANALYSIS"]
+ end
+
+ subgraph Access teams
+ FO["Front Office
(no permissions)"]
+ BO["Back Office
(no permissions)"]
+ end
+
+ FP[("Front Office
projects")]
+ BP[("Back Office
projects")]
+
+ Alice --> Devs
+ Alice --> FO
+ Bob --> Devs
+ Bob --> BO
+ Carol --> Auditors
+ Carol --> FO
+ Carol --> BO
+
+ FO -. ACL .-> FP
+ BO -. ACL .-> BP
+```
+
+Resulting effective access:
+
+| User | Can view | Can triage vulnerabilities on |
+|:------|:--------------------------------------|:------------------------------|
+| Alice | Front Office projects | none |
+| Bob | Back Office projects | none |
+| Carol | Front Office and Back Office projects | both portfolios |
+
+Adding a new domain becomes a single new access team and its ACL assignments.
+Granting an existing user analyst rights on that domain is a team membership
+change, not a per-project edit.
+
+### Inheritance through the project hierarchy
+
+ACL grants are inherited down the project hierarchy. Granting a team access to a
+parent project grants access to every descendant, current and future. Assigning
+teams at the top of a project tree is usually preferable to assigning them on
+every leaf.
+
+### Bypassing PAC
+
+The `PORTFOLIO_ACCESS_CONTROL_BYPASS` permission exempts a principal from PAC
+entirely: they see every project as if PAC were disabled. Reserve it for
+administrators and trusted automation that legitimately needs to operate across
+the full portfolio.
+
+### Project creation under PAC
+
+When an API key creates a project (for example, via BOM upload with
+`PROJECT_CREATION_UPLOAD`), the API key's team is added to the new project's
+ACL automatically.
+
+When a user creates a project, they must designate an owning team from those
+they belong to. The chosen team is added to the new project's ACL. A project
+created with no team assignment is invisible to everyone except administrators
+and holders of `PORTFOLIO_ACCESS_CONTROL_BYPASS` until one is assigned.
+
## Further reading
* [Permissions reference](../reference/permissions.md) for the full permissions table
diff --git a/docs/guides/administration/configuring-ldap.md b/docs/guides/administration/configuring-ldap.md
index 0082ec2..0d1cedf 100644
--- a/docs/guides/administration/configuring-ldap.md
+++ b/docs/guides/administration/configuring-ldap.md
@@ -4,6 +4,14 @@ Dependency-Track can authenticate users against an LDAP directory such as Micros
Active Directory, ApacheDS, or any other LDAP-compatible server. Once enabled, users
log in with their directory credentials rather than a locally managed password.
+## Authentication flow
+
+Dependency-Track authenticates LDAP users by first performing a service-account
+bind to locate the user's directory entry, then attempting a bind with the
+user's own credentials to verify their password. On success, the system grants
+access. With user provisioning enabled, Dependency-Track creates the account
+automatically on first login.
+
## Prerequisites
- A service account in the LDAP directory with read access to users and groups.
diff --git a/docs/guides/administration/configuring-oidc.md b/docs/guides/administration/configuring-oidc.md
index 4a63326..8c265d5 100644
--- a/docs/guides/administration/configuring-oidc.md
+++ b/docs/guides/administration/configuring-oidc.md
@@ -6,9 +6,18 @@ Dependency-Track supports SSO via [OpenID Connect](https://openid.net/specs/open
!!! note "Frontend configuration required"
OIDC requires configuration on both the **API server** and the **frontend**.
- The API server validates tokens; the frontend initiates the OIDC flow.
+ The API server validates tokens, while the frontend initiates the OIDC flow.
Configure both with the same issuer and client ID.
+## Authentication flow
+
+The frontend redirects the user to the identity provider's authorization
+endpoint. After the user authenticates, the IdP returns an ID token to the
+frontend, which forwards it to the API server for validation. The API server
+verifies the token against the IdP's discovery endpoint and extracts the
+username from the configured claim. With user provisioning enabled,
+Dependency-Track creates the account automatically on first login.
+
## Prerequisites
- An OIDC-compatible identity provider with a configured client (app).
diff --git a/docs/includes/abbreviations.md b/docs/includes/abbreviations.md
index e499267..2552578 100644
--- a/docs/includes/abbreviations.md
+++ b/docs/includes/abbreviations.md
@@ -12,6 +12,7 @@
*[NVD]: National Vulnerability Database
*[OIDC]: OpenID Connect
*[OSV]: Open Source Vulnerabilities
+*[PAC]: Portfolio Access Control
*[PURL]: Package URL, a standardized format for identifying software packages
*[SBOM]: Software Bill of Materials
*[SLO]: Service Level Objectives