What this is about
You manage groups through the admin API under /cias/admin/groups. The user interfaces for this call exactly these endpoints, see The admin interface.
The endpoints
| Call | Does |
|---|---|
GET /cias/admin/groups?query=…&page=0&size=50 | one page of groups, sorted by key. query searches key, name and description |
GET /cias/admin/groups/{key} | one group |
POST /cias/admin/groups | create a group |
PUT /cias/admin/groups/{key} | change name, description, roles and default group |
DELETE /cias/admin/groups/{key} | delete a group |
GET /cias/admin/groups/{key}/members?page=0&size=50 | one page of members, as IDs of user records |
POST /cias/admin/groups/{key}/members | add members |
POST /cias/admin/groups/{key}/members/remove | remove members |
GET /cias/admin/groups/of-user/{userId} | all groups of one person, not paged |
POST /cias/admin/groups/import | take over existing Keycloak groups |
POST /cias/admin/groups/reconcile | start a reconciliation with Keycloak, see Reconciliation with Keycloak |
Lists always come in pages: items, page, size, total, hasMore. Without a value you get 50 rows, at most 500. If you ask for more, you get 400 instead of silently fewer rows.
The checks
-
CIASPlatform administratorIs the caller logged in, and does their token carry a role that counts as platform administrator?↳ no 403
cias.authorization.denied, textnot permitted -
CIASGroupDoes the group exist (for everything except create)? Is the key still free (for create)?↳ no 404
cias.authorization.group-not-foundor 409cias.authorization.group-key-in-use -
CIASRolesIs every named role in the catalog?↳ no 404
cias.authorization.role-not-found -
CIASKeycloakWhen taking: did Keycloak accept the change?↳ no 503, CIAS stays unchanged
- Change saved
The 403 looks exactly like every other refusal of the permission check. CIAS writes the exact reason to the log.
Create a group
POST /cias/admin/groups
Authorization: Bearer <token of a platform administrator>
{
"key": "support",
"name": "Support 1st Level",
"description": "Everyone in phone support",
"roles": [
{ "client": null, "key": "user" },
{ "client": "cdms-backend", "key": "customer-read" },
{ "client": "crms-backend", "key": "ticket-edit" }
],
"defaultGroup": false
}HTTP 200
{
"key": "support",
"name": "Support 1st Level",
"description": "Everyone in phone support",
"roles": [
{ "client": null, "key": "user", "displayName": "User",
"scope": "PLATFORM", "effectiveInEveryTenant": true },
{ "client": "cdms-backend", "key": "customer-read", "displayName": "Read customers",
"scope": "PLATFORM", "effectiveInEveryTenant": false },
{ "client": "crms-backend", "key": "ticket-edit", "displayName": "Edit tickets",
"scope": "TENANT", "effectiveInEveryTenant": false }
],
"memberCount": 0,
"defaultGroup": false,
"syncState": "SYNCHRONIZED"
}| Field | Meaning |
|---|---|
key | required. Fixed forever, the name of the group in Keycloak |
name | optional, otherwise the key |
roles | the complete list. client: null is a realm role. If the list is missing, the group carries no roles |
defaultGroup | if missing, it is false. So a client that does not know the field never creates a default group by accident |
effectiveInEveryTenant | true only for realm roles. false means: this role drops out under a tenant with roles of its own, see Group roles under dynamic tenants |
syncState | SYNCHRONIZED when the copy is in Keycloak, otherwise PENDING |
A freshly created group has no members yet. So it does not give anyone anything yet.
The six variants
When: POST /cias/admin/groups
-
1CIASchecks key and roles, saves the group as
PENDING -
2CIAS→Keycloakcreates the group in the realm, marked with
cias-managed=true, sets roles and default group -
3CIASstores the Keycloak ID, sets
SYNCHRONIZEDResult: 200 with the group. If Keycloak cannot be reached, still 200, butsyncState: PENDING
When: PUT /cias/admin/groups/{key}, path and key in the body must match, otherwise 400
-
1CIAS→Keycloaktakes away first: roles that are no longer included and, if needed, the default group property
-
2CIASsaves name, description, roles, default group, sets
PENDING -
3CIAS→Keycloakthen adds: new roles, default group if needed; sets
SYNCHRONIZEDResult: 200. If the first Keycloak step fails: 503, nothing changed. If the last one fails: 200 withPENDING
When: DELETE /cias/admin/groups/{key}
-
1CIAS→Keycloakdeletes the copy of the group
-
2CIASdeletes the group and its membershipsResult: 204. Members keep their accounts and only lose what the group gave them. If Keycloak fails: 503, the group stays
When: POST …/members with { "userIds": ["5c9e…", "7a1b…"] }
-
1CIASsaves the memberships; anyone who is already a member simply stays one
-
2CIAS→Keycloakadds each person to the copy of the groupResult: 200 with the group. If Keycloak does not work for all of them: still 200, but
PENDING
When: POST …/members/remove with { "userIds": ["5c9e…"] }
-
1CIAS→Keycloakremoves each person from the copy of the group
-
2CIASdeletes the membershipsResult: 200. If Keycloak fails: 503, CIAS stays unchanged
When: POST /cias/admin/groups/import, no body
Takes over the groups that already exist in Keycloak and that CIAS does not manage yet. Details in the next section.
Result: 200 with a report
Changing roles means: send the whole list
There is no “add role” and no “remove role”. With PUT you always send the complete list. You remove a role by sending the list without it. Whatever you leave out goes away, in Keycloak too, even if it was the last role of a module.
The key cannot be changed. If a group should be called something else, change name.
Members are user records
userIds are the IDs of the user records in CIAS, not the Keycloak sub. How to find them is described in The user record. The list must not be empty, otherwise 400. You can add or remove several people at once, just like ticking boxes in an interface.
Take over existing Keycloak groups
A realm that existed before CIAS often contains groups that someone created in the Keycloak console. They carry no cias-managed mark, so CIAS does not touch them. With the import, CIAS takes them over.
-
1CIAS→Keycloakreads all top-level groups without the
cias-managedmark. Groups that Keycloak manages itself (attributes starting withkc., such as organization groups) are left out -
2CIASDoes CIAS already manage a group with this key? Then it is left untouched
-
3CIASAre all roles of the group in the catalog? Does every member have a user record in CIAS?
-
4CIASno → the group is skipped, with the reason in the report
-
5CIASsaves the group with roles, members and default group, exactly as in Keycloak
-
6CIAS→Keycloaksets the mark
cias-managed=true, nothing elseResult: The group now belongs to CIAS. Roles and members are unchanged
POST /cias/admin/groups/importHTTP 200
{
"found": 4,
"adopted": 2,
"alreadyKnown": 1,
"skipped": [
{ "group": "buchhaltung",
"reason": "it carries 1 role(s) the CIAS catalogue does not know (erp:invoice-approve) — their module has to declare them first, or the next reconciliation would take them off the group" }
]
}A group is taken over completely or not at all. Why so strict? Whatever CIAS manages, the reconciliation later writes back to Keycloak. If CIAS simply left out an unknown role, the next reconciliation would take it away from the group. If CIAS left out an unknown member, that person would be thrown out of the group. So: first have the module declare the missing roles and import the missing accounts, then repeat the import.
The import can safely be repeated. Groups that were taken over carry the mark and no longer show up in the next run. An interrupted run is finished the next time. alreadyKnown counts Keycloak groups without the mark whose name CIAS already uses for a group of its own. They stay untouched. The import does not take over subgroups, only the top level.
Errors at a glance
| Response | When |
|---|---|
400 cias.authorization.invalid-request | key missing, userIds empty, path and body name different groups, whitespace in a role name, page too large |
403 cias.authorization.denied | not a platform administrator |
404 cias.authorization.group-not-found | unknown group. GET /cias/admin/groups/{key} answers 404 without a body |
404 cias.authorization.role-not-found | a role is not in the catalog |
409 cias.authorization.group-key-in-use | the key is already taken |
| 503 | Keycloak cannot be reached, when taking |