Groups Endpoint
The /Groups endpoint manages SCIM Group resources for organizing users. SCIM (System for Cross-domain Identity Management) is the standard for syncing users and groups between systems. The resource shape comes from the SCIM 2.0 core schema, and the HTTP verbs and PATCH operations come from the SCIM 2.0 protocol.
In LumoAuth a SCIM Group is an organization role: adding a member grants that role, removing a member revokes it. Two rules follow from that:
- Every write on
/Groupsis refused with403when the organization has switched off Allow group operations (see provisioning policy). - Roles that make their members administrators can never be managed through SCIM (see Protected roles).
Every example uses the organization's SCIM provisioning token ($SCIM_TOKEN).
List Groups
GET
/orgs/\{orgId\}/api/v1/scim2.0/Groups
curl -X GET "https://app.lumoauth.dev/orgs/acme-corp/api/v1/scim2.0/Groups" \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Accept: application/scim+json"
Filtering
GET /Groups?filter=... accepts exactly one of these forms; anything else, including and / or combinations, returns 400 invalidFilter:
| Filter | Matches |
|---|---|
displayName eq "Engineering" (also co, sw) | Groups by name |
externalId eq "okta-00g1" | The group created with that externalId |
id eq "10" | One group by id |
members[value eq "123"] | Groups that user 123 belongs to |
POST /Groups/.search uses the general filter grammar over id, externalId, displayName, meta.created, meta.lastModified and isSoftDeleted.
Response
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 5,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "10",
"displayName": "Engineering",
"members": [
{"value": "123", "$ref": ".../Users/123", "display": "John Smith"},
{"value": "456", "$ref": ".../Users/456", "display": "Jane Doe"}
],
"meta": {
"resourceType": "Group",
"created": "2024-01-01T00:00:00Z",
"lastModified": "2024-06-15T12:30:00Z",
"location": "https://app.lumoauth.dev/orgs/acme-corp/api/v1/scim2.0/Groups/10",
"version": "W/\"3\""
}
}
]
}
Create Group
POST
/orgs/\{orgId\}/api/v1/scim2.0/Groups
curl -X POST "https://app.lumoauth.dev/orgs/acme-corp/api/v1/scim2.0/Groups" \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Marketing",
"members": [
{"value": "123"},
{"value": "456"}
]
}'
Update Group Members (PATCH)
Use PATCH to add or remove members without replacing the entire group:
# Add members
curl -X PATCH "https://app.lumoauth.dev/orgs/acme-corp/api/v1/scim2.0/Groups/10" \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{"op": "add", "path": "members", "value": [{"value": "789"}]}
]
}'
# Remove specific member
curl -X PATCH "https://app.lumoauth.dev/orgs/acme-corp/api/v1/scim2.0/Groups/10" \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{"op": "remove", "path": "members[value eq \"123\"]"}
]
}'
Delete Group
DELETE
/orgs/\{orgId\}/api/v1/scim2.0/Groups/\{id\}
Deleting a group removes every member from the role and then deletes the role. There is no soft delete for groups. System and privileged roles cannot be deleted (403, see below).
Protected roles
SCIM group membership can never hand out administrator authority. A group is refused for PUT, PATCH and DELETE when the underlying role is a system role (for example the built-in organization administrator role) or when it confers administrator authority. A role confers administrator authority when it holds at least one permission that lets its members change who can do what in the organization. The families are:
| Family | Permissions counted as administrative |
|---|---|
| Organization settings | settings.create, settings.edit, settings.delete, settings.manage |
| Users, roles, groups | users.create, users.edit, users.delete, roles.create, roles.edit, roles.delete, roles.assign-permissions, groups.create, groups.edit, groups.delete |
| Customer organizations | organizations.members.manage, organizations.invitations.manage |
| Identity providers and provisioning | idps.create, idps.edit, idps.delete, scim.create, scim.edit, scim.delete, scim.manage |
| Signing keys | signing_keys.create, signing_keys.edit, signing_keys.rotate, signing_keys.revoke, signing_keys.delete |
| OAuth clients | clients.create, clients.edit, clients.delete, clients.rotate-secret |
| AI agents, policies, approvals | agents.create, agents.edit, agents.delete, policies.create, policies.edit, policies.delete, jit.approve |
| Fine-grained authorization | zanzibar.create, zanzibar.edit, zanzibar.delete, abac.manage |
| Privacy and billing | gdpr.manage, gdpr.dpo, billing.manage |
| Platform | tenants.create, tenants.edit, tenants.delete |
Read-only permissions (*.view, audit.*, analytics.*, webhooks.*, branding.*) do not make a role administrative, so groups for ordinary job functions work as expected.
The refusal is a SCIM error:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "403",
"scimType": "mutability",
"detail": "System or privileged roles cannot be modified via SCIM"
}
(... cannot be deleted via SCIM for DELETE.) Creating a group whose name maps to a reserved slug such as admin is refused with 400 invalidValue. Administrators are assigned in the portal or the Admin API, where the same no privilege gain rule applies.
Common mistakes
- Okta "Push Groups" fails with 403 for one group only. That group maps to a role holding an administrative permission (table above). Keep administrators out of IdP-managed groups, or split the role.
- Every group push fails with 403. Allow group operations is off at
/orgs/{orgId}/portal/integrations/scim. 400 invalidFilterwhen looking a group up. Only the forms in Filtering are supported onGET /Groups; an unsupported filter is rejected instead of returning every group.400 invalidValueon create. The display name converts to a reserved slug (admin, and similar). Rename the group in the IdP.
Group Schema
| Attribute | Type | Required | Description |
|---|---|---|---|
id | string | - | Unique identifier (readOnly) |
displayName | string | Yes | Group display name |
externalId | string | No | External system identifier |
members | array | No | Group membership (User references) |
meta | object | - | Resource metadata (readOnly) |
Standards used on this page
| Plain name | Standard |
|---|---|
| SCIM 2.0 (user and group provisioning) | RFC 7642, RFC 7643 and RFC 7644 |
See the standards reference for what each one covers and how LumoAuth uses it.