Skip to content

Permissions & Roles

Chatto’s permissions system is built around two ideas: roles group people, and permissions describe capabilities. Every authenticated user has the implicit everyone role and may have additional roles such as moderator, admin, custom roles, or owner.

The current model is intentionally simple:

  • Owners are always allowed. A user is an owner if they have the durable owner role or a verified email listed in owners.emails.
  • Everyone else is permission-based. A non-owner action is allowed only when at least one applicable grant exists and no applicable deny exists.
  • Any deny wins. A deny attached to the user or to any of their roles blocks the action, regardless of other grants.
  • Room settings are local exceptions. Configure room-specific behavior in the room’s permissions first; use server-scope permissions for global defaults or global restrictions.

Every Chatto server starts with four system roles. You cannot delete them.

RoleDefault behavior
everyoneEvery authenticated user has this role. Fresh servers grant normal member defaults here: room discovery/joining, posting, thread posting, reactions, echoing thread replies, and deleting your own account.
moderatorAdds server-wide moderation defaults: viewing users, managing messages, and banning room members.
adminAdds broad server administration defaults, including room administration, role management, user administration, audit/system views, and message.manage.
ownerAlways has every permission virtually. Owner permissions are not stored as editable grants.

Roles still have a numeric position for display order and legacy event compatibility, but position is not an authorization rank.

When a user tries to do something, Chatto resolves the decision like this:

  1. DM privacy boundary. Some moderation-style permissions are always denied inside DMs. Owners do not get to browse or moderate other people’s private conversations.
  2. Owner override. Effective owners are allowed for every normal RBAC permission.
  3. Deny-wins resolution. For non-owners, Chatto collects applicable user and role decisions at server, group, and room scope. If any applicable decision is a deny, the action is denied.
  4. Allow if granted. If there is no deny and at least one applicable allow, the action is allowed.
  5. Default deny. If nothing grants the permission, the action is denied.

Permissions can be configured at different scopes:

ScopeMeaning
ServerGlobal defaults or restrictions across the whole server.
GroupDefaults or restrictions for a room group.
RoomLocal exceptions for one room.

Room-relevant permissions such as message.post, message.react, message.manage, room.join, and room.ban-member can be configured at room/group/server scope. Server-only permissions such as server.manage, role.manage, and admin.view-audit are configured only at server scope.

PermissionMeaning
message.postPost root messages and start DMs.
message.post-in-threadPost messages inside threads.
message.manageEdit or delete other users’ messages. Authors can edit/delete their own messages without this permission.
message.reactAdd or remove reactions.
message.echoEcho thread replies to the main channel.
room.listSee rooms in the directory and room lists.
room.joinJoin channel rooms.
room.createCreate channel rooms.
room.manageConfigure, rename, archive, or delete rooms.
room.ban-memberBan members from channel rooms.
role.manageCreate, edit, delete, reorder roles, and edit role permissions.
role.assignAssign or revoke roles for users.
user.manage-permissionsEdit direct per-user permission overrides.
user.delete-anyDelete any user’s account.
user.delete-selfDelete your own account.

The full list is visible in the admin UI.

Fresh development/bootstrap servers create announcements as a read-only room by denying message.post for everyone at room scope.

Because every authenticated user has everyone and any deny wins, this blocks root posting for all non-owner users, including admins and moderators. Owners can still post because owner permissions are virtual and cannot be denied through RBAC.

If you also want to prevent thread replies in announcements, deny message.post-in-thread for everyone in that room.

To temporarily freeze a room for all non-owner users:

  1. Open the room’s permissions.
  2. Deny message.post for everyone.
  3. Optionally deny message.post-in-thread and message.react as well.

Clear the room-level denials to restore the normal server defaults.

To stop one non-owner user from posting without changing their roles:

  1. Open the user’s member details in the admin UI.
  2. Under permission overrides, deny message.post at server scope.
  3. Optionally deny message.post-in-thread, message.react, and message.echo.

User-level denies beat role grants for non-owners. They do not restrict effective owners.

Giving one user a room-specific moderation grant

Section titled “Giving one user a room-specific moderation grant”

To let one non-owner user moderate one room:

  1. Open the user’s member details.
  2. Grant message.manage scoped to that room.

This works as long as no applicable deny blocks message.manage for that user. If a deny exists on the user or one of their roles, clear that deny instead of adding more grants.

Use custom roles for repeated patterns across multiple users:

  1. Create a role in the admin UI.
  2. Assign permissions to that role.
  3. Assign the role to users.

Custom roles are permission bundles. They do not take precedence over other roles, and they cannot override a deny from another role the user also has.

Owners and admins are deliberately different:

  • Owners always receive all permissions and cannot be locked out through RBAC state. Owner permission rows are shown as read-only green checks in the UI.
  • Admins receive broad default grants, but they are still ordinary non-owner users for permission resolution. A deny can restrict an admin.

Use owners.emails in chatto.toml as the recovery path. The email must be verified before it makes the user an effective owner.

DMs use the same permission names where they make sense, but Chatto keeps a hard privacy boundary around private conversations. Moderation and room-administration permissions such as message.manage, message.echo, room.manage, room.list, and room.create are denied in DMs regardless of role grants.

Access to a DM comes from being a participant in that conversation. Owners cannot read into DMs or moderate DM contents unless they are a participant and the action is a normal participant action.

What you want to doWhere
Set recovery ownersowners.emails in chatto.toml
Create or edit rolesAdmin UI -> Roles
Assign roles to usersAdmin UI -> Members
Edit role permissionsAdmin UI -> Roles -> [role name]
Configure room-specific behaviorRoom settings -> Permissions
Set per-user overridesAdmin UI -> Members -> [user]
Reset everything to defaultschatto reset rbac