
# Roles & RBAC

Sovrium uses **role-based access control (RBAC)** with an optional layer of [groups](/en/docs/auth-groups). Every authenticated user has exactly one role; roles are arranged in a numeric **hierarchy**; and [table permissions](/en/docs/table-permissions) reference roles to gate create/read/update/delete and per-field access.

```yaml
auth:
  strategies:
    - type: emailAndPassword
  defaultRole: member
  roles:
    - name: editor
      description: Can edit content
      level: 30
```

## Built-in Roles

Three roles ship with every auth-enabled app. They are always available and **cannot be redefined** by custom roles.

| Role     | Level | Access                                                            |
| -------- | ----- | ----------------------------------------------------------------- |
| `admin`  | 80    | Full access — manage users, roles, and settings; all permissions. |
| `member` | 40    | Standard access to application resources.                         |
| `viewer` | 10    | Read-only access.                                                 |

## Role Hierarchy & Levels

Each role has a numeric `level`. Higher levels are more privileged. The level establishes an ordering used by permission resolution and by features that compare role seniority (for example, an admin-equivalent role is one at the highest configured level).

Built-in levels are fixed at `admin=80`, `member=40`, `viewer=10`. Custom roles slot anywhere along this scale via their own `level`:

```yaml
auth:
  roles:
    - name: editor
      level: 30 # between viewer (10) and member (40)
    - name: moderator
      level: 50 # between member (40) and admin (80)
```

:::callout
**Most-permissive-wins.** When a user's permissions come from multiple sources (their role and their groups), the union of granted operations applies. If the role grants `read` and a group grants `update`, the user gets both. See [Groups](/en/docs/auth-groups).
:::

## Custom Role Definitions

`auth.roles` is an array of custom role definitions layered on top of the built-ins. An empty array (or omitting the field) means only the built-in roles exist.

```yaml
auth:
  roles:
    - name: editor
      description: Can edit content
      level: 30
    - name: moderator
      level: 20
    - name: contributor
```

| Property         | Description                                                                                                                                                               |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`           | **Required.** Role identifier. Lowercase, alphanumeric, hyphens; must start with a letter. Must be unique and must not collide with a built-in role name or a group name. |
| `description`    | Human-readable description of the role's purpose.                                                                                                                         |
| `level`          | Hierarchy level (higher = more privileged). Built-in references: `admin=80`, `member=40`, `viewer=10`.                                                                    |
| `defaultLanding` | Per-role post-login landing URL. See [Post-Login Landing](/en/docs/auth-post-login).                                                                                      |
| `pickerLanding`  | Multi-record fallback for a templated `defaultLanding`. See [Post-Login Landing](/en/docs/auth-post-login).                                                               |

**Naming rules** — role names match `^[a-z][a-z0-9-]*$`:

| Name              | Valid? | Reason                   |
| ----------------- | ------ | ------------------------ |
| `editor`          | ✅     | lowercase letters        |
| `content-manager` | ✅     | hyphen allowed           |
| `Editor`          | ❌     | uppercase not allowed    |
| `123role`         | ❌     | must start with a letter |

Validation rejects:

- Duplicate custom role names.
- Custom names that collide with built-in roles (`admin`, `member`, `viewer`).
- Custom names that collide with a [group](/en/docs/auth-groups) name (roles and groups share a namespace).

## Default Role

`auth.defaultRole` is the role assigned to new users on registration. It defaults to `member` when omitted, and must reference a built-in role **or** a custom role defined in `auth.roles`.

```yaml
auth:
  strategies:
    - type: emailAndPassword
  defaultRole: viewer # new users start read-only
  roles:
    - name: editor
      level: 30
```

| Property      | Description                                                                            |
| ------------- | -------------------------------------------------------------------------------------- |
| `defaultRole` | Role granted to newly registered users. Built-in or custom name. Defaults to `member`. |

:::callout
A `defaultRole` referencing an undefined custom role fails validation at startup. Define the role in `auth.roles` before naming it as the default. Setting `defaultRole: viewer` is a common pattern for apps where new users should be read-only until an admin promotes them.
:::

## Admin Roles

When `auth` is configured, the admin user-management surface is always mounted (there is no separate toggle). The **first user to register becomes an admin** (`firstUserAdmin`). Admins can:

- Create users (`POST /api/auth/admin/create-user`) — including when `allowSignUp: false`.
- Invite users with single-use tokens (`POST /api/auth/admin/invite-user`).
- Assign and change roles.
- Impersonate users for support workflows.
- Ban / unban users.

The highest-level role is treated as admin-equivalent for these checks, so a custom role at `level: 80` (or higher) participates in admin gating alongside the built-in `admin` role.

## How Roles Gate Data

Roles do not grant data access on their own — they are referenced by each table's `permissions` block. A role with no matching permission entry has no access to that table. See [Table Permissions](/en/docs/table-permissions) for the full create/read/update/delete/restore/comment and per-field model, including how `group:`-prefixed entries combine with roles.

## Related Pages

- [Authentication Overview](/en/docs/auth-overview) — default roles in context.
- [Groups](/en/docs/auth-groups) — many-to-many membership layered on roles.
- [Post-Login Landing](/en/docs/auth-post-login) — per-role landing rules.
- [Table Permissions](/en/docs/table-permissions) — where roles actually gate data.
