Skip to main content

Access control API

Platform access control: users, groups, roles, and the permission catalog.

This page lists 26 endpoints (OpenAPI tag control-plane-access). It is generated from openapi.json; see the REST API overview for authentication, CSRF and error conventions.

MethodPathOperation idNotes
GET/api/control-plane/access/effectiveget_effective_accessGET /access/effective — the effective-access resolver (AX-3): for a principal, enumerate the platform roles, permissions (with provenance), workspace membe...
GET/api/control-plane/access/roleslist_roles
POST/api/control-plane/access/rolescreate_role
GET/api/control-plane/access/roles/{id}get_role
PATCH/api/control-plane/access/roles/{id}update_role
DELETE/api/control-plane/access/roles/{id}delete_role
GET/api/control-plane/access/roles/{id}/assigneeslist_role_assigneesGET /access/roles/\{id\}/assignees — the role's current assignees (users by email, groups by name), so the admin console can drill into who holds a role.
PUT/api/control-plane/access/roles/{id}/permissionsset_role_permissions
GET/api/control-plane/access/who-can-accesswho_can_accessGET /access/who-can-access — the reverse of /access/effective (AX-3): for one object (kind + id), enumerate every principal who can reach it and why ...
GET/api/control-plane/groupslist_groups
POST/api/control-plane/groupscreate_group
PATCH/api/control-plane/groups/{id}rename_group
DELETE/api/control-plane/groups/{id}delete_group
GET/api/control-plane/groups/{id}/memberslist_group_membersGET /groups/\{id\}/members — the group's current members, so the admin console can prefill and diff its manage-members dialog.
POST/api/control-plane/groups/{id}/membersadd_group_member
DELETE/api/control-plane/groups/{id}/members/{user_id}remove_group_member
POST/api/control-plane/groups/{id}/rolesassign_group_role
DELETE/api/control-plane/groups/{id}/roles/{role_id}unassign_group_role
GET/api/control-plane/permissionslist_permissionsGET /permissions — the code-defined catalog (egret_core::rbac), each permission annotated with the role names that currently grant it.
GET/api/control-plane/userslist_users
POST/api/control-plane/userscreate_user
PATCH/api/control-plane/users/{id}update_user
DELETE/api/control-plane/users/{id}delete_userDELETE /users/\{id\} — hard-delete a user (Task 4).
POST/api/control-plane/users/{id}/passwordreset_passwordPOST /users/\{id\}/password — admin reset of a LOCAL user's password.
POST/api/control-plane/users/{id}/rolesassign_user_role
DELETE/api/control-plane/users/{id}/roles/{role_id}unassign_user_role

GET /api/control-plane/access/effective​

Operation id: get_effective_access. Auth: Session cookie. Forbidden (403): Missing role:read permission.

GET /access/effective — the effective-access resolver (AX-3): for a principal, enumerate the platform roles, permissions (with provenance), workspace memberships, object grants, and denies that feed them. Read-only, so it gates on role:read. principal_id accepts a raw UUID or a user email / group name (resolved to a UUID; 404 if unknown).

ParameterInTypeRequiredDescription
principal_typequerystringyesuser | group
principal_idquerystringyesUUID, or a user email / group name

Response 200 (application/json): EffectiveAccess

FieldTypeRequiredDescription
principalPrincipalInfoyes
platform_rolesRoleSource[]yes
permissionsEffectivePermission[]yes
workspacesWorkspaceMembership[]yes
objectsObjectGrant[]yes
deniesDenyEntry[]yes
StatusMeaning
200Effective access for the principal
400Invalid principal_type
401Not authenticated
403Missing role:read permission
404No such principal
500Internal error

GET /api/control-plane/access/roles​

Operation id: list_roles. Auth: Session cookie. Forbidden (403): Missing role:read permission.

Response 200 (application/json): array of RoleDto

FieldTypeRequiredDescription
idstring (uuid)yes
scopestringyes
namestringyes
descriptionstringyes
permissionCountinteger (int64)yes
assigneeCountinteger (int64)yes
parentRoleIdstring (uuid), nullablenoThe role this one inherits permissions from (same scope). None at the top of a chain.
inheritedPermissionsstring[]yesEffective-minus-own permissions, for read-only display. Populated on the single-role GET; empty on the list endpoint.
StatusMeaning
200RBAC roles with permission and assignee counts
401Not authenticated
403Missing role:read permission
500Internal error

POST /api/control-plane/access/roles​

Operation id: create_role. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

Request body (application/json): CreateRoleInput

FieldTypeRequiredDescription
scopestringyes
namestringyes
descriptionstringno
parentRoleIdstring (uuid), nullableno

Response 201 (application/json): RoleDto

FieldTypeRequiredDescription
idstring (uuid)yes
scopestringyes
namestringyes
descriptionstringyes
permissionCountinteger (int64)yes
assigneeCountinteger (int64)yes
parentRoleIdstring (uuid), nullablenoThe role this one inherits permissions from (same scope). None at the top of a chain.
inheritedPermissionsstring[]yesEffective-minus-own permissions, for read-only display. Populated on the single-role GET; empty on the list endpoint.
StatusMeaning
201Role created
400Invalid scope
401Not authenticated
403Requires platform_admin
409A role with this name already exists
500Internal error

GET /api/control-plane/access/roles/{id}​

Operation id: get_role. Auth: Session cookie. Forbidden (403): Missing role:read permission.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesRole id

Response 200 (application/json): RoleDto

FieldTypeRequiredDescription
idstring (uuid)yes
scopestringyes
namestringyes
descriptionstringyes
permissionCountinteger (int64)yes
assigneeCountinteger (int64)yes
parentRoleIdstring (uuid), nullablenoThe role this one inherits permissions from (same scope). None at the top of a chain.
inheritedPermissionsstring[]yesEffective-minus-own permissions, for read-only display. Populated on the single-role GET; empty on the list endpoint.
StatusMeaning
200A single role with its parent and inherited permissions
401Not authenticated
403Missing role:read permission
404No such role
500Internal error

PATCH /api/control-plane/access/roles/{id}​

Operation id: update_role. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesRole id

Request body (application/json): UpdateRoleInput

FieldTypeRequiredDescription
descriptionstringyes
parentRoleIdstring (uuid), nullableno

Response 200 (application/json): RoleDto

FieldTypeRequiredDescription
idstring (uuid)yes
scopestringyes
namestringyes
descriptionstringyes
permissionCountinteger (int64)yes
assigneeCountinteger (int64)yes
parentRoleIdstring (uuid), nullablenoThe role this one inherits permissions from (same scope). None at the top of a chain.
inheritedPermissionsstring[]yesEffective-minus-own permissions, for read-only display. Populated on the single-role GET; empty on the list endpoint.
StatusMeaning
200Role description updated
401Not authenticated
403Requires platform_admin
404No such role
500Internal error

DELETE /api/control-plane/access/roles/{id}​

Operation id: delete_role. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesRole id
StatusMeaning
204Role deleted
401Not authenticated
403Requires platform_admin
404No such role
409Seeded roles cannot be deleted
500Internal error

GET /api/control-plane/access/roles/{id}/assignees​

Operation id: list_role_assignees. Auth: Session cookie. Forbidden (403): Missing role:read permission.

GET /access/roles/\{id\}/assignees — the role's current assignees (users by email, groups by name), so the admin console can drill into who holds a role. Read-only, so it gates on role:read.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesRole id

Response 200 (application/json): array of RoleAssigneeDto

FieldTypeRequiredDescription
kindstringyes
namestringyes
StatusMeaning
200The role's current assignees (users and groups)
401Not authenticated
403Missing role:read permission
500Internal error

PUT /api/control-plane/access/roles/{id}/permissions​

Operation id: set_role_permissions. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesRole id

Request body (application/json): SetPermissionsInput

FieldTypeRequiredDescription
permissionsstring[]yes
StatusMeaning
204Role permission set replaced
400Unknown permission key
401Not authenticated
403Requires platform_admin
500Internal error

GET /api/control-plane/access/who-can-access​

Operation id: who_can_access. Auth: Session cookie. Forbidden (403): Missing role:read permission.

GET /access/who-can-access — the reverse of /access/effective (AX-3): for one object (kind + id), enumerate every principal who can reach it and why (direct object grants, the object's workspace-role holders, and platform admins). Read-only, so it gates on role:read. An unknown kind or a missing object surfaces egret_core::Error::NotFound → 404.

ParameterInTypeRequiredDescription
kindquerystringyesObject kind: chart | dashboard | dataset | notebook | saved_query | folder | app
idquerystring (uuid)yesObject UUID

Response 200 (application/json): WhoCanAccess

FieldTypeRequiredDescription
objectObjectRefyes
entriesAccessEntry[]yes
StatusMeaning
200Principals who can access the object
401Not authenticated
403Missing role:read permission
404Unknown object kind or no such object
500Internal error

GET /api/control-plane/groups​

Operation id: list_groups. Auth: Session cookie. Forbidden (403): Missing group:read permission.

Response 200 (application/json): array of GroupDto

FieldTypeRequiredDescription
idstring (uuid)yes
namestringyes
sourcestringyes
memberCountinteger (int64)yes
rolesstring[]yes
StatusMeaning
200Platform groups with member counts and roles
401Not authenticated
403Missing group:read permission
500Internal error

POST /api/control-plane/groups​

Operation id: create_group. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing group:create permission.

Request body (application/json): CreateGroupInput

FieldTypeRequiredDescription
namestringyes

Response 201 (application/json): GroupDto

FieldTypeRequiredDescription
idstring (uuid)yes
namestringyes
sourcestringyes
memberCountinteger (int64)yes
rolesstring[]yes
StatusMeaning
201Local group created
400Invalid input
401Not authenticated
403Missing group:create permission
409A group with this name already exists
500Internal error

PATCH /api/control-plane/groups/{id}​

Operation id: rename_group. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing group:update permission.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesGroup id

Request body (application/json): RenameGroupInput

FieldTypeRequiredDescription
namestringyes
StatusMeaning
204Group renamed
401Not authenticated
403Missing group:update permission
409Cannot rename an OIDC-synced group; or another group already has the new name; or grants or rule exemptions still name the old or the new name (the message lists them to a caller with policy:read, and otherwise gives only their count;...
500Internal error

DELETE /api/control-plane/groups/{id}​

Operation id: delete_group. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing group:delete permission.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesGroup id
StatusMeaning
204Group deleted
401Not authenticated
403Missing group:delete permission
409Cannot delete an OIDC-synced group; or grants or rule exemptions still name the group (the message lists them to a caller with policy:read, and otherwise gives only their count; remove them first)
500Internal error

GET /api/control-plane/groups/{id}/members​

Operation id: list_group_members. Auth: Session cookie. Forbidden (403): Missing group:read permission.

GET /groups/\{id\}/members — the group's current members, so the admin console can prefill and diff its manage-members dialog. Read-only, so it gates on group:read rather than group:manage_members.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesGroup id

Response 200 (application/json): array of GroupMemberDto

FieldTypeRequiredDescription
idstring (uuid)yes
emailstringyes
namestringyes
StatusMeaning
200The group's current members
401Not authenticated
403Missing group:read permission
500Internal error

POST /api/control-plane/groups/{id}/members​

Operation id: add_group_member. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesGroup id

Request body (application/json): AddMemberInput

FieldTypeRequiredDescription
userIdstring (uuid)yes
StatusMeaning
204User added to the group
401Not authenticated
403Requires platform_admin
404No such group or user
409Cannot add members to an OIDC-synced group
500Internal error

DELETE /api/control-plane/groups/{id}/members/{user_id}​

Operation id: remove_group_member. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesGroup id
user_idpathstring (uuid)yesUser id to remove
StatusMeaning
204User removed from the group
401Not authenticated
403Requires platform_admin
500Internal error

POST /api/control-plane/groups/{id}/roles​

Operation id: assign_group_role. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesGroup id

Request body (application/json): AssignRoleInput

FieldTypeRequiredDescription
roleIdstring (uuid)yes
StatusMeaning
204Role assigned to the group
401Not authenticated
403Requires platform_admin
404No such group or role
500Internal error

DELETE /api/control-plane/groups/{id}/roles/{role_id}​

Operation id: unassign_group_role. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesGroup id
role_idpathstring (uuid)yesRole id to unassign
StatusMeaning
204Role unassigned from the group
401Not authenticated
403Requires platform_admin
404No such role
409Would remove the last platform admin
500Internal error

GET /api/control-plane/permissions​

Operation id: list_permissions. Auth: Session cookie. Forbidden (403): Missing role:read permission.

GET /permissions — the code-defined catalog (egret_core::rbac), each permission annotated with the role names that currently grant it.

Response 200 (application/json): array of PermissionGroupDto

FieldTypeRequiredDescription
groupstringyes
permissionsPermissionDto[]yes
StatusMeaning
200The code-defined permission catalog, grouped, annotated with granting roles
401Not authenticated
403Missing role:read permission
500Internal error

GET /api/control-plane/users​

Operation id: list_users. Auth: Session cookie. Forbidden (403): Missing user:read permission.

Response 200 (application/json): array of ControlPlaneUserDto

FieldTypeRequiredDescription
idstring (uuid)yes
emailstringyes
namestringyes
providerstringyes
statusstringyes
rolesstring[]yes
groupsstring[]yes
StatusMeaning
200Platform users with their roles and groups
401Not authenticated
403Missing user:read permission
500Internal error

POST /api/control-plane/users​

Operation id: create_user. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing user:create permission.

Request body (application/json): CreateUserInput

FieldTypeRequiredDescription
emailstringyes
namestringyes
passwordstringyes

Response 201 (application/json): ControlPlaneUserDto

FieldTypeRequiredDescription
idstring (uuid)yes
emailstringyes
namestringyes
providerstringyes
statusstringyes
rolesstring[]yes
groupsstring[]yes
StatusMeaning
201Local user created
400Invalid input
401Not authenticated
403Missing user:create permission
409A user with this email already exists
500Internal error

PATCH /api/control-plane/users/{id}​

Operation id: update_user. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing user:update (or user:disable) permission.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesUser id

Request body (application/json): UpdateUserInput

FieldTypeRequiredDescription
namestring, nullableno
statusstring, nullableno

Response 200 (application/json): ControlPlaneUserDto

FieldTypeRequiredDescription
idstring (uuid)yes
emailstringyes
namestringyes
providerstringyes
statusstringyes
rolesstring[]yes
groupsstring[]yes
StatusMeaning
200User profile and/or status updated (disabling also revokes the user's live sessions immediately)
400Invalid status value, or a caller disabling their own account
401Not authenticated
403Missing user:update (or user:disable) permission
404No such user
409Would remove the last platform admin
500Internal error

DELETE /api/control-plane/users/{id}​

Operation id: delete_user. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing user:delete permission.

DELETE /users/\{id\} — hard-delete a user (Task 4). Guards: not yourself, not the last active platform admin (guard_not_last_admin, shared with the disable branch of update_user). Cleans up the user's sessions, group memberships, and platform role/permission grants, then removes the row itself, in one transaction (UserRepo::hard_delete).

ParameterInTypeRequiredDescription
idpathstring (uuid)yesUser id
StatusMeaning
204User hard-deleted along with sessions/group memberships/grants
400Caller attempted to delete their own account
401Not authenticated
403Missing user:delete permission
404No such user
409Would remove the last platform admin
500Internal error

POST /api/control-plane/users/{id}/password​

Operation id: reset_password. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing user:update permission.

POST /users/\{id\}/password — admin reset of a LOCAL user's password. Rehashes the new plaintext, then revokes the user's live sessions (mirrors the disable branch of update_user) so a session issued under the old password can't linger.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesUser id

Request body (application/json): ResetPasswordInput

FieldTypeRequiredDescription
passwordstringyes
StatusMeaning
204Password reset; the user's live sessions are revoked
400Empty password, or the target is not a local account
401Not authenticated
403Missing user:update permission
404No such user
500Internal error

POST /api/control-plane/users/{id}/roles​

Operation id: assign_user_role. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesUser id

Request body (application/json): AssignRoleInput

FieldTypeRequiredDescription
roleIdstring (uuid)yes
StatusMeaning
204Role assigned to the user
401Not authenticated
403Requires platform_admin
404No such user or role
500Internal error

DELETE /api/control-plane/users/{id}/roles/{role_id}​

Operation id: unassign_user_role. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Requires platform_admin.

ParameterInTypeRequiredDescription
idpathstring (uuid)yesUser id
role_idpathstring (uuid)yesRole id to unassign
StatusMeaning
204Role unassigned from the user
401Not authenticated
403Requires platform_admin
404No such role
409Would remove the last platform admin
500Internal error