Skip to main content

Groups and automatic membership

What a group is for, how a membership rule is written, the six operators, and the three moments a rule actually runs — because it is not the ones you would expect.

Written for whoever runs IT10 min readUpdated

A group is a named set of people. Qorionix supports two ways of filling one: you add members yourself, or you write a rule that describes who belongs. This article covers both.

Groups you fill yourself

A group has a name, an optional description and a member count. Names must be unique within your organisation; reusing one returns group already exists with HTTP 409, and renaming a group onto an existing name returns group name already exists. Acting on a group that has been deleted returns group not found.

Members are added and removed one at a time, or in bulk through a single patch that takes a list to add and a list to remove. The bulk form is what the Identity → Groups page uses when you tick several people and save, and it is the right tool for a reorganisation — it is one operation, so you are not left half-way through if something fails.

Each membership row records whether the person was added directly by a human or derived from a rule. That distinction exists so that a rule can later add and remove its own members without disturbing the ones you placed by hand — see When rules are evaluated below for exactly when that happens.

The group list is served under two addresses, one of which is a legacy spelling kept alive so existing scripts and the older console pages keep working. They are the same groups; there is no second set hiding behind the other URL.

The group profile

Groups carry a free-form profile document, structurally identical to the one on a user record: any keys you like, no fixed set, no schema and no validation. It is intended for attributes an external directory wants to keep alongside a group, such as a description in another system's vocabulary or an owner reference.

Two honest caveats. The ordinary group API neither returns the profile nor accepts one — the group object you get back has an id, a name, a description, a member count and timestamps, and nothing else. The only thing that reads or writes a group profile today is inbound directory synchronisation. And exactly as with the user profile, nothing validates the contents. If you are not synchronising from another directory, the group profile is not a field you can use.

You may also see a group type recorded against a group. Four values exist in the schema, and the intended meaning of one of them is this group is filled by a rule. Nothing in the platform branches on the value: it is a label, it is not returned by the group API, and a rule points at its target group regardless of what the group's type says. Do not use it to reason about how a group is maintained.

How a membership rule is written

A rule is a separate object from the group it fills. It has a name, a description, a target group, an active flag, and a list of conditions. It is not a text expression — you are not writing a search string or a filter language. Each condition is three fields: which attribute to look at, how to compare it, and what to compare it against.

A rule with two conditions
{
  "name": "Finance team",
  "description": "Everyone in the finance department in the Dublin office",
  "target_group_id": "...the group this rule fills...",
  "is_active": true,
  "conditions": [
    { "field": "department", "operator": "eq",         "value": "Finance" },
    { "field": "office",     "operator": "startsWith", "value": "Dublin" }
  ]
}

field names a key inside the user's profile document. That is the whole addressable surface — it is not the email address, not the first or last name, and not the status or user type. If you want to build a rule on department, department has to be a key you are already writing into each person's profile. A rule referring to a key nobody has does not fail; it behaves in the way described in the warning below.

The six comparison operators. Note the capitalisation on the last three.
OperatorTrue whenExample
eqThe value matches exactly.department eq Finance
neThe value does not match.employment ne Contractor
containsThe value contains the text anywhere inside it.title contains Manager
startsWithThe value begins with the text.office startsWith Dublin
endsWithThe value ends with the text.costCentre endsWith -EU
presentThe attribute has any value at all.lineManager present

Three limits follow from that design and are worth knowing before you plan a group structure around it.

  • Conditions are combined with AND only. Every condition must be true. There is no OR, no bracketing, and no way to express finance or legal in one rule. Two overlapping populations need two rules pointing at the same group.
  • There is no negation beyond ne. You cannot write not (title contains Manager).
  • Every value is text. There are no numeric or boolean comparisons, so headcount greater than five is not expressible and a profile value of true is compared as the five characters true.

When rules are evaluated

A rule runs at exactly three moments, and knowing which three is the whole of operating this feature well.

When somebody joins the organisation
Joining is the first moment a tenant's rules can apply to a person at all — before the membership row exists there is no organisation whose rules could be evaluated. This covers an invitation being accepted and a bulk import.
When a user record is updated
Including a profile attribute changing, which is the case that makes rules useful: somebody's department changes, and their group membership follows.
When somebody presses **Re-evaluate everyone**
The explicit sweep, on Identity → Group rules. This is the one you need after editing a rule, because editing a rule affects everybody and re-running every user on every rule save would be unbounded write amplification from one tenant's button press. The console says so when you save one: Rule saved and active. Membership does not change until you re-evaluate, or until an affected user is next created or edited.

The sweep is bounded at 5,000 users in one pass, and it reports the count it evaluated so you can tell a partial sweep from a complete one rather than being told done either way. It returns users_evaluated, memberships_added, memberships_removed, any groups it skipped, and any per-user errors — one user's failure does not abandon the sweep.

Reconciliation is also deliberately best-effort at the two automatic points. If it fails after a user is updated, the update is not rolled back and the call does not fail — telling somebody their save did not happen when it did would invite a retry that re-applies an edit already applied. Membership converges on the next edit or the next sweep.

Before you activate a rule, use Show me who this matches. It runs the real matcher against your users and reports Would be added to {group} and Would be removed from {group} without changing anything, up to a preview limit of 2,000 users scored and 50 members listed — and it tells you when it truncated, so a partial answer is not mistaken for a complete one.

The rule that matches everyone

Two shapes of rule will silently match your entire staff, and neither is rejected when you save it. Now that rules do run, this matters immediately rather than eventually: use the preview before you activate one, and read the number it reports rather than the list.

A rule with no conditions
An empty condition list is accepted. Every condition passing vacuously means every user matches. There is no validation requiring at least one condition, and no warning. It is easy to create by saving a rule before you have added the first condition.
A condition on an attribute nobody has
When a user's profile has no such key, the comparison is not skipped — the absent value is turned into text first, and what it becomes is not an empty string. The consequence is that present is true for an attribute that is absent, and ne is true against every value you could compare it with. A rule saying lineManager is present therefore matches everyone, including the people who have no line manager recorded, which is the exact opposite of what it reads as.

What to do next

  1. Users and the directory — the profile document that group rules read, and why nothing validates it.
  2. The permission model — where access actually comes from, given that it does not come from groups.
  3. Building a role that grants exactly enough — the tool to reach for when what you really wanted was to give a group of people a particular level of access.

Was this article wrong?

If a procedure here does not match what you see, or a limit we described has changed, tell us and we will fix the page. Email us about this article, or see how to get help if you need an answer rather than a correction.

Everything in identity and access