> ## Documentation Index
> Fetch the complete documentation index at: https://www.osohq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# User Groups

User groups let you assign roles to groups; each user inherits the group's roles, reducing the need to assign roles individually.

## Implementation

The core idea of user groups is that a user inherits all roles from the groups that user belongs to. Assigning a user to a group is sufficient to grant them all roles assigned to that group.

```polar theme={null}
actor User { }

# Model groups as actors to assign roles to them
actor Group { }

resource Repository {
  roles = ["reader"];
  permissions = ["read"];

  "read" if "reader";
}

# Users inherit roles from groups
# `user` has `role` on `resource` if
has_role(user: User, role: String, resource: Resource) if
  # there exists a `group`
  group matches Group and
  # `user` is in the group
  has_group(user, group) and
  # the `group` has `role` on `resource`
  has_role(group, role, resource);

test "group members can read repositories" {
  setup {
    has_role(Group{"anvil-readers"}, "reader", Repository{"anvil"});

    has_group(User{"alice"}, Group{"anvil-readers"});
    has_group(User{"bob"}, Group{"anvil-readers"});
    has_group(User{"charlie"}, Group{"anvil-readers"});
  }

  assert allow(User{"alice"}, "read", Repository{"anvil"});
  assert allow(User{"bob"}, "read", Repository{"anvil"});
  assert allow(User{"charlie"}, "read", Repository{"anvil"});
}
```

We've assigned the `reader` role to the `anvil-readers` group, and then added Alice, Bob, and Charlie to that group. Now they can all read the `anvil` repository.

## Nested groups

You can extend this pattern by allowing groups to be members of other groups, forming a hierarchy. Users inherit roles from every group in the hierarchy.

Implement this with a recursive rule: a user is a member of a group if they belong to any subgroup of that group.

```polar theme={null}
has_group(user: User, group: Group) if
  g matches Group and
  has_group(user, g) and
  has_group(g, group);
```
