Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 216 additions & 51 deletions docs/reference/rest_api_groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,39 @@

## Groups

Query and manage groups.
Query and manage groups (roles).

!!! info "Authentication required"

Requests to search REST API endpoints require authentication. Results sets
are limited to max 10 results per query (i.e. pagination is not supported).
Requests to search REST API endpoints require authentication.
Creation, update and deletion all require authentication as administrator or superuser.
Access to **managed** groups is restricted to user administrators (see
[Managed vs unmanaged groups](#managed-vs-unmanaged-groups) below).

### Search groups
### Managed vs unmanaged groups

- **Managed groups**: Created via the admin UI or REST API and fully
controllable by admin users with administration moderation permission (e.g.
administrators and superusers). They support the usual CRUD operations unless
their names are protected (e.g. `admin`, `superuser-access`).
- **Unmanaged groups**: Typically synced or created by the system (for example
through identity providers). They are readable by authenticated users but are
not editable through the REST API or admin UI unless you are a superuser.

Search for groups
### Search groups

`GET /api/groups`

**Parameters**

| Name | Type | Location | Description |
| -------- | ------ | -------- | ------------------------------------ |
| `q` | string | query | Search query used to filter results. |
| `accept` | string | header | - `application/json` |
| Name | Type | Location | Description |
|--------|---------|----------|-------------|
| `q` | string | query | Search query used to filter results. |
| `accept` | string | header | - `application/json` |
| `sort` | string | query | Sort search results. Built-in options are `"bestmatch"`, `"name"`, `"name_desc"`, `"managed"`, `"unmanaged"`. Default is `"bestmatch"` when `q` is present, otherwise `"name"`. |
| `size` | integer | query | Items per page (default: `20`, max: `50`). |
| `page` | integer | query | Page number (default: `1`). |
| `is_managed` | boolean | query | Filter by management state (`true` or `false`). |

**Query string syntax**

Expand All @@ -29,7 +43,7 @@ The query string syntax is based on [ElasticSearch's query string syntax](https:
**Request**

```http
GET /api/groups?q=admin HTTP/1.1
GET /api/groups?q=admin&sort=managed&is_managed=true HTTP/1.1
```

**Response**
Expand All @@ -39,46 +53,61 @@ HTTP/1.1 200 OK
Content-Type: application/json

{
"hits": {
"hits": [
{
"id": "admin",
"revision_id": 1,
"created": "2022-05-23T11:48:27.205711+00:00",
"updated": "2022-05-23T11:49:14.411568+00:00",
"name": null,
"is_managed": true,
"links": {
"avatar": "https://127.0.0.1:5000/api/groups/admin/avatar.svg",
"self": "https://127.0.0.1:5000/api/groups/admin"
"hits": {
"hits": [
{
"id": "admin",
"created": "2026-02-04T09:29:59.790372+00:00",
"updated": "2026-02-04T09:30:23.892939+00:00",
"links": {
"self": "https://127.0.0.1:5000/api/groups/admin",
"avatar": "https://127.0.0.1:5000/api/groups/admin/avatar.svg"
},
"revision_id": 1770197423,
"name": "admin",
"description": null,
"is_managed": true
}
],
"total": 1
},
"aggregations": {
"is_managed": {
"buckets": [
{
"key": "true",
"doc_count": 1,
"label": "Managed",
"is_selected": true
}
],
"label": "Management state"
}
}
],
"total": 1
},
"links": {
"self": "https://127.0.0.1:5000/api/groups?page=1&size=10&sort=name"
},
"sortBy": "name"
},
"sortBy": "managed",
"links": {
"self": "https://127.0.0.1:5000/api/groups?is_managed=true&page=1&q=admin&size=20&sort=managed"
}
}
```

### Get a group

`GET /api/group/{id}`
`GET /api/groups/{id}`

Both authenticated and unauthenticated access is possible.
Authenticated users can access **unmanaged** groups. Managed groups are only
visible to user administrators or superusers.

**Parameters**

| Name | Type | Location | Description |
| -------- | ------ | -------- | -------------------- |
| `id` | string | path | The group identifier. |
| Name | Type | Location | Description |
|----------|--------|----------|-------------|
| `id` | string | path | The group identifier (UUID). |
| `accept` | string | header | - `application/json` |

**Errors**

- **403**: The group does not exist.
- **403**: The group is not accessible to the caller.

**Request**

Expand All @@ -94,35 +123,160 @@ HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "admin",
"revision_id": 1,
"created": "2022-05-23T11:48:27.205711+00:00",
"updated": "2022-05-23T11:49:14.411568+00:00",
"name": null,
"is_managed": true,
"id": "bbe66a83-6925-44b9-80e6-eba824b5c9e7",
"created": "2026-02-04T10:17:11.029064+00:00",
"updated": "2026-02-04T10:17:11.029082+00:00",
"links": {
"avatar": "https://127.0.0.1:5000/api/groups/admin/avatar.svg",
"self": "https://127.0.0.1:5000/api/groups/admin"
}
"self": "https://127.0.0.1:5000/api/groups/bbe66a83-6925-44b9-80e6-eba824b5c9e7",
"avatar": "https://127.0.0.1:5000/api/groups/bbe66a83-6925-44b9-80e6-eba824b5c9e7/avatar.svg"
},
"revision_id": 1770200231,
"name": "data-stewards",
"description": "Local data steward team",
"is_managed": true
}
```

### Create a group

`POST /api/groups`

**Parameters**

| Name | Type | Location | Description |
|----------------|--------|----------|-------------|
| `name` | string | body | Required. Must start with a letter and contain only letters, numbers, hyphens or underscores (max 80 chars). |
| `description` | string | body | Optional. Max 255 chars. |
| `accept` | string | header | - `application/json` |

**Errors**

- **400**: Validation error (invalid name or description length).
- **403**: Caller lacks `user_management_action` permissions or tries to create a protected group name.

**Request**

```http
POST /api/groups HTTP/1.1
Content-Type: application/json

{
"name": "data-stewards",
"description": "Local data steward team"
}
```

**Response**

```http
HTTP/1.1 201 CREATED
Content-Type: application/json

{
"id": "bbe66a83-6925-44b9-80e6-eba824b5c9e7",
"created": "2026-02-04T10:17:11.029064+00:00",
"updated": "2026-02-04T10:17:11.029082+00:00",
"links": {
"self": "https://127.0.0.1:5000/api/groups/bbe66a83-6925-44b9-80e6-eba824b5c9e7",
"avatar": "https://127.0.0.1:5000/api/groups/bbe66a83-6925-44b9-80e6-eba824b5c9e7/avatar.svg"
},
"revision_id": 1770200231,
"name": "data-stewards",
"description": "Local data steward team",
"is_managed": true
}
```

### Update a group

`PUT /api/groups/{id}`

**Parameters**

| Name | Type | Location | Description |
|---------------|--------|----------|-------------|
| `id` | string | path | The group identifier (UUID). |
| `name` | string | body | Optional. Must satisfy the same pattern as creation. |
| `description` | string | body | Optional. Max 255 chars. |
| `accept` | string | header | - `application/json` |

**Errors**

- **400**: Validation error (e.g. description too long).
- **403**: The group is not accessible to the caller.

**Request**

```http
PUT /api/groups/bbe66a83-6925-44b9-80e6-eba824b5c9e7 HTTP/1.1
Content-Type: application/json

{
"description": "Updated description"
}
```

**Response**

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "bbe66a83-6925-44b9-80e6-eba824b5c9e7",
"created": "2026-02-04T10:17:11.029064+00:00",
"updated": "2026-02-04T10:26:45.322262+00:00",
"links": {
"self": "https://127.0.0.1:5000/api/groups/bbe66a83-6925-44b9-80e6-eba824b5c9e7",
"avatar": "https://127.0.0.1:5000/api/groups/bbe66a83-6925-44b9-80e6-eba824b5c9e7/avatar.svg"
},
"revision_id": 1770200805,
"name": "data-stewards",
"description": "Updated description",
"is_managed": true
}
```

### Delete a group

`DELETE /api/groups/{id}`

**Parameters**

| Name | Type | Location | Description |
|----------|--------|----------|-------------|
| `id` | string | path | The group identifier (UUID). |
| `accept` | string | header | - `application/json` |

**Errors**

- **403**: The group is not accessible to the caller.

**Request**

```http
DELETE /api/groups/2d3b5de5-5d64-4f9d-9c4c-2fd70047f90a HTTP/1.1
```

**Response**

```http
HTTP/1.1 204 No Content
```

### Get avatar for group

`GET /api/groups/{id}/avatar.svg`

Both authenticated and unauthenticated access is possible.

**Parameters**

| Name | Type | Location | Description |
| ---- | ------ | -------- | -------------------- |
| `id` | string | path | The group identifier. |
| Name | Type | Location | Description |
|------|--------|----------|-------------|
| `id` | string | path | The group identifier (UUID). |

**Errors**

- **403**: The group does not exist.
- **403**: The group is not accessible to the caller.

**Request**

Expand All @@ -147,3 +301,14 @@ ETag: "L#f06292"
</text>
</svg>
```

### Permissions and protected names

- Only identities with the user management action permission (e.g. user with
`administration-moderation` role) or the system process can create, update, or delete managed
groups.
- Some identifiers are protected (e.g. `admin`, `superuser-access`,
`administration`, `administration-moderation`) and cannot be created or
modified via the REST API. They can only be changed by system processes.
- Unmanaged groups remain visible to authenticated users but cannot be mutated
by administrators unless they are superusers.
11 changes: 11 additions & 0 deletions docs/releases/vNext/version-vNext.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ and digital assets management! Version Next will be maintained until at least 6

## What's new?

### Administration panel: users and roles

In v14, the administration panel adds users/roles improvements, including
role-aware views and groups CRUD support.

!!! Danger "v14 upgrade impact"
Access checks now resolve roles by **role id** (not role name).
If you previously relied on role **names** for access control, you must
migrate all existing logic and related references to role ids after
upgrading to v14, or access behavior may break.

### Record deletion

You can now allow users to delete, or request deletion of, their own records in accordance with any required criteria you may have. When enabled the default behaviour is that records can be deleted by their owners within 30 days of publication and record owners can request deletion outside this period. Deletion requests are visible within the admin panel and the user's request dashboard.
Expand Down
29 changes: 29 additions & 0 deletions docs/use/administration.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,35 @@ You can:
For more details on communities, see [Communities](../maintenance/architecture/communities.md).
For API usage, see the [REST API for Communities](../reference/rest_api_communities.md).

_Introduced in v14._

## Users & roles

You can now manage **roles (groups)** directly from the administration panel.

!!! Danger "v14 upgrade impact"
Access checks now resolve roles by **role id** (not role name).
If you previously relied on role **name** for access control, you must
migrate all existing logic and related references to role ids after
upgrading to v14, or access behavior may break.

- **List and search** roles at `/administration/roles` with sorting (A–Z, Z–A,
managed first/last) and a facet to filter managed vs unmanaged roles.
- **Create** new roles, providing a unique name and optional description. Names
must start with a letter and only contain letters, numbers, hyphens or
underscores (max 80 characters).
- **Edit** or **delete** existing roles from their detail page.
edits/deletes via the UI and the REST API. This is configurable with `USERS_RESOURCES_PROTECTED_GROUP_NAMES`.
`administration-moderation`, and `superuser-access` are shielded from admin
edits/deletes via the UI and the REST API. This is configurable with `USERS_RESOURCES_PROTECTED_GROUP_NAMES`.

Navigation is restricted to users who have access to user administration
(`administration` + `administration-moderation` roles or superusers). Unauthorized
access attempts receive a 403 error.

!!! note
Unmanaged roles can only be edited by the system.

## Deposits

### Records
Expand Down