---
summary: Users have direct roles + roles inherited via group membership. Permissions
  are checked against site or content scope.
title: RBAC
path: concepts/rbac
status: published
---

# Role-based access control

Permissions in ScaiCMS are slug-based (`content.create`, `docs.write`,
`api_key.create`, …). They are granted **via roles**, and roles attach to
users either directly or through group membership.

## The model

```
User --has--> UserRole --grants--> Role --has--> Permission(s)
           \
            +--member-of--> Group --has--> GroupRole --grants--> Role
```

Effectively, a user's permissions are the union of all direct + group-
inherited role permissions.

## Scopes

A `UserRole` can be:

- **Global** — applies everywhere.
- **Site-scoped** — applies only in one site.
- **Content-type-scoped** — applies only within one content type.
- **Subtree-scoped** — applies under a content path.

When a permission check runs, the system computes the user's permissions
*in the current request's context* (site + optional content). This is
implemented in `core/permissions.py:get_user_permissions`.

## Standard roles

Seeded by `python -m scaicms.scripts.seed`:

- `super_admin` — every permission, global.
- `site_admin` — all site/content/asset perms scoped to one site.
- `editor` — content create/read/update + asset upload.
- `viewer` — content read only.

You can build your own roles in the admin UI under **Roles**.

## Docs-specific permissions

The documentation subsystem ships its own perms:

- `docs.read` — read non-public namespaces (public ones don't require it).
- `docs.write` — upsert/delete pages.
- `docs.manage` — namespaces, versions, mounts, index admin.

See also [API keys](/docs/scaicms/concepts/api-keys) for how scope
qualifiers on a key narrow these even further.
