> For the complete documentation index, see [llms.txt](https://docs.opendatadiscovery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opendatadiscovery.org/configuration-and-deployment/enable-security/authorization/permissions.md).

# Permissions

There are 5 types of permissions in ODD Platform:

* [Data entity permissions](#data-entity-permissions): Actions related to specific data assets, such as tables, data streams, or dashboards.
* [Term permissions](#term-permissions): Actions concerning the management of the [Business Glossary](/features/data-glossary/business-glossary.md), e.g. terms and their definitions.
* [Query Example permissions](#query-example-permissions): Actions for creating and managing SQL query examples linked to datasets and terms.
* [Lookup table permissions](#lookup-table-permissions): Actions for creating and maintaining operator-managed reference tables — both the table schema and the rows stored in it.
* [Management permissions](#management-permissions): High-level administrative actions for managing the platform's infrastructure and configuration, such as creating data sources, managing users, or defining access control rules.

{% hint style="info" %}
This list is generated from the [`Permission` enum](https://github.com/opendatadiscovery/odd-platform/blob/main/odd-platform-specification/components.yaml) in the Platform's OpenAPI spec (`odd-platform-specification/components.yaml`). If a new permission appears in the API but is missing from this page, or vice versa, it is a bug — please open an issue or PR.
{% endhint %}

This is the full list of permissions divided by types:

#### Data entity permissions

* `DATA_ENTITY_ADD_TERM`. Allows adding a term to a data entity.
* `DATA_ENTITY_ADD_TO_GROUP`. Allows adding a data entity to a manually created group. **Operator caveat**: the permission is scoped against the **child entity** in the URL, not the parent group — a caller with this permission against entity X can place X into **any** manually-created DEG in the catalog, including DEGs owned by other teams. There is no per-DEG authorisation today, and the mutation emits no Activity Feed event. See [Data Entity Groups & Domains → Managing DEG Membership](/features/data-discovery/groups-domains.md#managing-deg-membership).
* `DATA_ENTITY_ALERT_CONFIG_UPDATE`. Allows configuring alert settings for a data entity (e.g., backwards-incompatible schema change alert, failed data quality test, failed job, distribution anomaly) and the time period to disable notifications.
* `DATA_ENTITY_ALERT_RESOLVE`. Allows resolving alerts for a data entity.
* `DATA_ENTITY_ATTACHMENT_MANAGE`. Allows adding, deleting, and managing file attachments and links for a data entity. (See [Attachments and links](/features/data-discovery/attachments.md).)
* `DATA_ENTITY_CUSTOM_METADATA_CREATE`. Allows creating custom metadata field values on a data entity, and minting new INTERNAL field rows in the deployment-wide field catalogue as a side effect of the create path. **Operator caveat**: the auto-create-on-miss side-channel makes this an indirect grant of catalogue-write — a caller can mint new field names visible to every other authenticated user on their next autocomplete keystroke. See [Custom metadata → Known limitations](/features/data-discovery/custom-metadata.md#known-limitations-and-operator-caveats).
* `DATA_ENTITY_CUSTOM_METADATA_DELETE`. Allows deleting a custom metadata field value from a data entity. The catalogue row is not affected by this operation (the field remains visible in the autocomplete picker on other entities). See [Custom metadata](/features/data-discovery/custom-metadata.md).
* `DATA_ENTITY_CUSTOM_METADATA_UPDATE`. Allows editing an existing custom metadata field value on a data entity. **Operator caveat**: the platform's update endpoint is declared `upsert*` in the API spec but the underlying SQL is a pure `UPDATE` — issuing a PUT for a field that has not previously been assigned on the target entity silently no-ops (HTTP 200 OK, empty body, "Metadata successfully updated." toast). Pre-flight with a GET, or switch to the Create endpoint on miss. See [Custom metadata → Known limitations](/features/data-discovery/custom-metadata.md#known-limitations-and-operator-caveats).
* `DATA_ENTITY_DELETE_FROM_GROUP`. Allows removing a data entity from a manually created group. **Operator caveat**: same write-collaborative posture as `DATA_ENTITY_ADD_TO_GROUP` — the permission is bound to the child entity in the URL, not the parent group; `DELETE` is silently idempotent (returns `204` on no-op without an Activity Feed event). See [Data Entity Groups & Domains → Managing DEG Membership](/features/data-discovery/groups-domains.md#managing-deg-membership).
* `DATA_ENTITY_DELETE_TERM`. Allows removing a term from a data entity.
* `DATA_ENTITY_DESCRIPTION_UPDATE`. Allows editing and deleting a data entity's custom description. **Operator caveat**: description text is persisted verbatim with no write-time HTML sanitisation, and the Markdown renderer is configured with `rehype-raw` and no `rehype-sanitize` — raw HTML embedded in the description renders as live markup for every catalog reader. The same write-collaborative posture applies to five sibling Markdown surfaces (per-column description, term definition, Query Example body, Lookup Table cell values, Slack notification body). See [Entity description → Security caveat](/features/data-discovery/entity-description.md#security-caveat-stored-xss-family-across-six-markdown-surfaces) for the operator-trust framing.
* `DATA_ENTITY_GROUP_UPDATE`. Allows editing a manually created data entity group.
* `DATA_ENTITY_INTERNAL_NAME_UPDATE`. Allows editing and deleting a data entity's business name. (See [Business names](/features/data-discovery/business-names.md).)
* `DATA_ENTITY_OWNERSHIP_CREATE`. Allows creating ownership for a data entity.
* `DATA_ENTITY_OWNERSHIP_DELETE`. Allows deleting ownership from a data entity.
* `DATA_ENTITY_OWNERSHIP_UPDATE`. Allows editing the title of a data entity ownership.
* `DATA_ENTITY_STATUS_UPDATE`. Allows changing the lifecycle status of a data entity (e.g., stable, deprecated, deleted, draft, unassigned). (See [Data entity statuses](/features/data-discovery/statuses.md).)
* `DATA_ENTITY_TAGS_UPDATE`. Allows editing a data entity's tags. **Operator caveat**: this is one of four permissions through which novel tag names mint new rows in the global tag directory — granting it to rank-and-file users widens vocabulary governance beyond `TAG_CREATE`. See [Manual Object Tagging → Known limitations and operator caveats](/features/data-discovery/tagging.md#known-limitations-and-operator-caveats).
* `DATASET_FIELD_ADD_TERM`. Documented as: allows linking a business glossary term to a specific field within a dataset. **Operator caveat — silently-misgated endpoint pair**: the platform's authorization wiring crosses two endpoints at adjacent lines today. The dataset-field term-add endpoint (`POST /api/datasetfields/{dataset_field_id}/terms`) is enforced against `DATA_ENTITY_ADD_TERM` at runtime, not `DATASET_FIELD_ADD_TERM` — UI gates on the documented permission, so the Add-term button is enabled for `DATASET_FIELD_ADD_TERM` holders but the server returns `403` silently. Separately, the alert-status PUT (`PUT /api/alerts/{alert_id}/status`) is enforced against `DATASET_FIELD_ADD_TERM` rather than `DATA_ENTITY_ALERT_RESOLVE` — granting this permission also grants alert-resolution on any entity. See [Per-column annotation → Known limitations](/features/data-discovery/per-column-annotation.md#known-limitations-and-operator-caveats) for the wiring-bug pair and the workaround.
* `DATASET_FIELD_DELETE_TERM`. Allows removing a linked business glossary term from a specific field within a dataset. See [Per-column annotation](/features/data-discovery/per-column-annotation.md).
* `DATASET_FIELD_DESCRIPTION_UPDATE`. Allows editing the description of an individual dataset field. The description is rendered through the same Markdown pipeline as the entity-level description and inherits the same security caveat — see [Entity description → Security caveat](/features/data-discovery/entity-description.md#security-caveat-stored-xss-family-across-six-markdown-surfaces) and [Per-column annotation](/features/data-discovery/per-column-annotation.md).
* `DATASET_FIELD_ENUMS_UPDATE`. Allows editing a dataset field's enum values. **Operator caveat**: the endpoint behind this permission is operationally bulk-replace (despite its `createEnumValue` operationId) — a partial submission soft-deletes every pre-existing enum row not present in the body. See [Per-column annotation → Known limitations](/features/data-discovery/per-column-annotation.md#known-limitations-and-operator-caveats).
* `DATASET_FIELD_INTERNAL_NAME_UPDATE`. Allows editing the business name of an individual dataset field. (See [Business names](/features/data-discovery/business-names.md) and [Per-column annotation](/features/data-discovery/per-column-annotation.md).)
* `DATASET_FIELD_TAGS_UPDATE`. Allows adding or removing tags from an individual dataset field. **Operator caveat**: novel tag names mint new rows in the global tag directory through this path; submitting an empty tag list silently clears every operator-curated (INTERNAL-origin) tag on the column. The audit feed event for column-level tag changes is `DATASET_FIELD_TAGS_UPDATED` (full before/after payload). See [Manual Object Tagging → Known limitations and operator caveats](/features/data-discovery/tagging.md#known-limitations-and-operator-caveats) and [Per-column annotation → Known limitations](/features/data-discovery/per-column-annotation.md#known-limitations-and-operator-caveats).
* `DATASET_TEST_RUN_SET_SEVERITY`. Allows setting severity for a dataset's quality tests.

#### Term permissions

* `TERM_CREATE`. Allows creating a new term in the business glossary.
* `TERM_DELETE`. Allows deleting a term from the business glossary.
* `TERM_OWNERSHIP_CREATE`. Allows creating ownership for a term.
* `TERM_OWNERSHIP_DELETE`. Allows deleting ownership from a term.
* `TERM_OWNERSHIP_UPDATE`. Allows editing the title of a term ownership.
* `TERM_TAGS_UPDATE`. Allows editing tags for a term. **Operator caveat**: novel tag names mint new rows in the global tag directory through this path. **No activity-feed event is emitted today** when term tags change — compliance / audit workflows depending on tag-change history must instrument this path externally. See [Manual Object Tagging → Known limitations and operator caveats](/features/data-discovery/tagging.md#known-limitations-and-operator-caveats).
* `TERM_UPDATE`. Allows editing the name, namespace, and definition of a term.

#### Query Example permissions

* `QUERY_EXAMPLE_CREATE`. Allows creating a query example.
* `QUERY_EXAMPLE_DATASET_CREATE`. Allows linking a query example to a dataset.
* `QUERY_EXAMPLE_DATASET_DELETE`. Allows unlinking a query example from a dataset.
* `QUERY_EXAMPLE_DELETE`. Allows deleting a query example.
* `QUERY_EXAMPLE_TERM_CREATE`. Allows linking a query example to a term.
* `QUERY_EXAMPLE_TERM_DELETE`. Allows unlinking a query example from a term.
* `QUERY_EXAMPLE_UPDATE`. Allows editing a query example.

#### Lookup table permissions

* `LOOKUP_TABLE_CREATE`. Allows creating a lookup table.
* `LOOKUP_TABLE_DATA_CREATE`. Allows adding data rows to a lookup table.
* `LOOKUP_TABLE_DATA_DELETE`. Allows deleting data rows from a lookup table.
* `LOOKUP_TABLE_DATA_UPDATE`. Allows editing data rows in a lookup table.
* `LOOKUP_TABLE_DEFINITION_CREATE`. Allows defining the structure (columns) of a lookup table.
* `LOOKUP_TABLE_DEFINITION_DELETE`. Allows deleting the structure (columns) of a lookup table.
* `LOOKUP_TABLE_DEFINITION_UPDATE`. Allows modifying the structure (columns) of a lookup table.
* `LOOKUP_TABLE_DELETE`. Allows deleting a lookup table.
* `LOOKUP_TABLE_UPDATE`. Allows editing the name and description of a lookup table.

#### Management permissions

* `COLLECTOR_CREATE`. Allows registering a new metadata collector.
* `COLLECTOR_DELETE`. Allows deleting a collector.
* `COLLECTOR_TOKEN_REGENERATE`. Allows regenerating the security token for a collector. **Operational caveat**: regeneration invalidates the prior token immediately — there is no grace period. The Collector process must be redeployed with the new token before existing ingestion stops.
* `COLLECTOR_UPDATE`. Allows editing a collector's configuration.
* `DATA_ENTITY_GROUP_CREATE`. Allows creating a new data entity group.
* `DATA_SOURCE_CREATE`. Allows creating a new data source connection.
* `DATA_SOURCE_DELETE`. Allows deleting a data source.
* `DATA_SOURCE_TOKEN_REGENERATE`. Allows regenerating the security token for a data source. **Operational caveat**: regeneration invalidates the prior token immediately — there is no grace period. The push-client must be redeployed with the new token before existing ingestion stops.
* `DATA_SOURCE_UPDATE`. Allows editing an existing data source's configuration.
* `DIRECT_OWNER_SYNC`. Allows associating a user with an owner without an approval request. **Composition caveat**: when the holder submits the home-page form with an owner name that does not exist in the catalog, the platform creates the owner on the requester's behalf and immediately binds them to it — in a single POST. Grant this permission only to principals you also trust to mint owner names (typically a service identity, not an end-user policy). See [User-owner association → How DIRECT\_OWNER\_SYNC changes the user-side flow](/configuration-and-deployment/enable-security/authorization/user-owner-association.md#how-direct_owner_sync-changes-the-user-side-flow).
* `NAMESPACE_CREATE`. Allows creating a new namespace via `POST /api/namespaces`. **Operator caveat — four sister-service side-doors**: four other parent permissions (`DATA_SOURCE_CREATE`, `DATA_SOURCE_UPDATE`, `TERM_CREATE`, `COLLECTOR_CREATE`, `DATA_ENTITY_GROUP_CREATE`) silently mint namespace rows through their `namespace_name` form field. Granting any of those parent permissions is an indirect grant of namespace-creation rights. See [Namespaces → Auto-create side-door](/features/management/namespaces.md#auto-create-side-door) for the four-vertex cluster and the operator-side mitigation.
* `NAMESPACE_DELETE`. Allows soft-deleting a namespace. **Operator caveat — cascade-block**: the delete is blocked with `CascadeDeleteException` (HTTP 400, error code `USR004`) when any of four referent tables (live data sources, live collectors, live terms, non-deleted data entities) still references the namespace. See [Namespaces → Cascade-on-delete guard](/features/management/namespaces.md#cascade-on-delete-guard) for the operator workflow and the partial-unique-index reincarnation behaviour after a successful soft-delete.
* `NAMESPACE_UPDATE`. Allows editing an existing namespace.
* `OWNER_ASSOCIATION_MANAGE`. Allows approving or denying user-owner association requests on the **Management → Associations → New requests** sub-tab. Also gates visibility of the Associations Management tab itself. Does **not** grant the admin direct-bind affordance — that requires `OWNER_RELATION_MANAGE` (see below). See [User-owner association → Approving incoming requests](/configuration-and-deployment/enable-security/authorization/user-owner-association.md#approving-incoming-requests-new-requests-tab).
* `OWNER_CREATE`. Allows creating a new owner entity via `POST /api/owners`. **Note:** three other service-tier code paths also mint Owner rows without consulting this permission — see [Owners → Three service-tier side-doors](/configuration-and-deployment/enable-security/authorization/owners.md#3-three-service-tier-side-doors-mint-owner-rows-without-owner_create).
* `OWNER_DELETE`. Allows deleting an owner via `DELETE /api/owners/{id}`. The delete is gated on no remaining ownership relations, term-ownership relations, or user-Owner bindings — operators see a `CascadeDeleteException` if any of those are still attached.
* `OWNER_RELATION_MANAGE`. Allows directly creating or removing the binding between a user and an owner — the **Create association** button in the Management → Associations header, and the per-row **Remove** on the Active associations sub-tab. Operators with this permission bypass the user-self-request and admin-approve workflow entirely. See [User-owner association → Creating a binding directly](/configuration-and-deployment/enable-security/authorization/user-owner-association.md#creating-a-binding-directly-create-association) and [Removing an existing binding](/configuration-and-deployment/enable-security/authorization/user-owner-association.md#removing-an-existing-binding-active-associations-tab). **Downstream-impact note:** the binding this permission creates is the single load-bearing anchor for the `/api/dataentities/my[/upstream|/downstream]` lineage triplet — every regression at the binding-resolution step has cross-owner blast radius on the lineage neighbourhood; see [Data Lineage → My-objects triplet](/features/data-lineage.md#my-objects-triplet-composition-anchor-architecture) for the architecture.
* `OWNER_UPDATE`. Allows editing an existing owner via `PUT /api/owners/{id}`. **Destructive-API caveat:** PUT with an empty (or absent) `roles` array silently removes every existing role binding from the Owner — see [Owners → PUT with empty roles destroys all role bindings](/configuration-and-deployment/enable-security/authorization/owners.md#4-put-apiownersid-with-empty-or-absent-roles-silently-destroys-all-role-bindings) for the safe-pattern fetch-modify-write workflow.

{% hint style="info" %}
**There is no `OWNER_READ` permission.** `GET /api/owners` is reachable to any authenticated user (and anonymous under `auth.type=DISABLED`) — it is part of the [read-collaborative posture on Management catalogs](#management-permissions) documented in the warning admonition at the bottom of this section.
{% endhint %}

* `POLICY_CREATE`. Allows creating a new access policy.
* `POLICY_DELETE`. Allows deleting an access policy.
* `POLICY_UPDATE`. Allows editing an existing access policy.
* `ROLE_CREATE`. Allows creating a new user role.
* `ROLE_DELETE`. Allows deleting a user role.
* `ROLE_UPDATE`. Allows editing an existing user role.
* `TAG_CREATE`. Allows creating a new tag. **Operator caveat**: `TAG_CREATE` is not the only path that mints new tags — four `*_TAGS_UPDATE` permissions (data entity, dataset field, term) plus collector ingestion all silently create tag rows for novel names. See [Manual Object Tagging → Known limitations and operator caveats](/features/data-discovery/tagging.md#known-limitations-and-operator-caveats).
* `TAG_DELETE`. Allows deleting a tag.
* `TAG_UPDATE`. Allows editing an existing tag.

{% hint style="warning" %}
**Read access on Management catalogs is granted to every authenticated user by design.** None of the Management permissions above gates the corresponding GET endpoint — withholding `OWNER_CREATE`, `NAMESPACE_CREATE`, `DATA_SOURCE_CREATE`, etc. does **not** restrict reads of the matching catalog. The endpoints below fall through to the platform's catch-all "any authenticated user" rule:

* `GET /api/owners` — every owner row (name, roles, provider mapping).
* `GET /api/owners/providers` — the active identity providers list.
* `GET /api/owner_association_request/activity` — the resolved-associations log (the **History** sub-tab; see [User-owner association → Auditing past association requests](/configuration-and-deployment/enable-security/authorization/user-owner-association.md#auditing-past-association-requests-history-tab)).
* `GET /api/namespaces` — every namespace, including names that may reveal organisational structure.
* `GET /api/datasources` — every registered data source (URL, ODDRN, namespace).
* `GET /api/collectors` — every collector, including a partially-redacted token until **Regenerate** is invoked.
* `GET /api/titles` — every catalog title vocabulary entry.

Operators who want to restrict read access on a Management catalog cannot do so through this permission set today. Plan deployments accordingly — anything sensitive enough to require read-side RBAC belongs on a different surface.
{% endhint %}

#### Comprehensive permissions

* `ALL`. Includes all permissions above.

## Permission read surface (two-endpoint orchestration)

Integrators consuming the platform's permission catalogue via the API need both of the endpoints below — the two scopes are orthogonal and the API does not unify them into a single call.

| Endpoint                                            | Scope                             | What it returns                                                                                                                                                                 | Example resource types                               |
| --------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `GET /api/resource/{type}/{id}/permissions`         | Contextual / resource-scoped      | The permissions the caller holds **in the named resource's context** (per-entity, per-term, per-query-example).                                                                 | `DATA_ENTITY`, `TERM`, `QUERY_EXAMPLE`               |
| `GET /api/identity/whoami` → `Identity.permissions` | Non-contextual / management-scope | The permissions the caller holds **globally** for management operations — Policy / Role / Owner / Datasource / Collector / Namespace / Tag / Lookup Table / Query Example CRUD. | (returned as a flat permission list, no resource ID) |

{% hint style="warning" %}
**`PermissionResourceType.MANAGEMENT` is a valid spec enum value but the runtime rejects it on the contextual endpoint.** The OpenAPI `PermissionResourceType` schema declares four values (`DATA_ENTITY`, `TERM`, `QUERY_EXAMPLE`, `MANAGEMENT`). Calling `GET /api/resource/MANAGEMENT/{id}/permissions` returns **HTTP 400 USR001** with the body `Resource type MANAGEMENT does not have context` — management-scope permissions are intentionally returned by the `/api/identity/whoami` endpoint, not the contextual one. SDK code generated from the spec that builds a 4-way switch over `PermissionResourceType` and dispatches all four to the contextual endpoint will see unexpected 400 responses on `MANAGEMENT` calls; route those to `whoami` instead. A spec-side tightening is tracked upstream.
{% endhint %}

### Five categories versus four resource types

The five permission groupings on this page (Data entity / Term / Query Example / Lookup table / Management) are an operator-readable taxonomy — they correspond to where permissions appear in the Management UI and how the runtime services consume them. The `PermissionResourceType` enum in the OpenAPI spec has **four values** because `LOOKUP_TABLE_*` permissions are stored within the Management bucket on the read surface (the runtime treats them as non-contextual / management-scope and returns them from `/api/identity/whoami`, not from `GET /api/resource/LOOKUP_TABLE/...` — there is no `LOOKUP_TABLE` resource type at the API contract).

An integrator dispatching from the four-value enum gets every permission the caller holds; the five-category page taxonomy is the framing operators use when reading the catalogue.

## Surfaces without per-resource permission gating today

Some read surfaces that an operator might assume are gated by a per-resource permission are reachable to any authenticated caller. The Management catalogs above (`GET /api/owners`, `GET /api/namespaces`, `GET /api/datasources`, …) are one such cluster — documented in the read-collaborative-posture warning above. The other cluster operators routinely meet is **dataset structure / version reads**:

* `GET /api/datasets/{data_entity_id}/structure` — the latest schema of any dataset.
* `GET /api/datasets/{data_entity_id}/structure/{version_id}` — any historical schema revision.
* `GET /api/datasets/{data_entity_id}/structure/diff?first_version_id=…&second_version_id=…` — the side-by-side diff between any two revisions.

The path component `{data_entity_id}` is consumed by the controller but **not** used by the underlying query — the query filters on `version_id` alone. Any authenticated caller enumerating `version_id` integers reads any dataset's schema; under `auth.type=DISABLED`, anonymously. The page-side detail (and the multi-tenant operator-mitigation table) lives on [Dataset schema diff → Known limitations](/features/data-discovery/schema-diff.md#known-limitations-and-operator-caveats).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.opendatadiscovery.org/configuration-and-deployment/enable-security/authorization/permissions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
