MokoNtfy layers a small, explicit access model on top of ntfy. This reference explains the coarse role hierarchy, how ownership is protected and handed off, custom RBAC roles, and how it all composes with groups and protected topics.
The role hierarchy: owner > admin > user
Every account has one coarse role:
- user — a normal account; access is governed entirely by topic ACLs (its own grants, group grants and the Everyone grant).
- admin — bypasses every access-control check and can open the Site Administration area.
- owner — the single highest account. An owner is a superset of admin (also bypasses every check) and additionally holds the owner-only powers, chiefly role management.
Both admin and owner bypass capability checks, so custom roles (below) only ever gate delegated, non-admin access.
How the owner role is minted
Owner is deliberately hard to obtain — it cannot be set like a normal role. The ordinary role-setting paths (creating a user, changing a role in the admin UI or via ntfy user change-role) accept only user or admin; owner is rejected there.
- Bootstrap (one time). On a server with no owner yet, an existing admin is promoted with the CLI-only
ntfy user set-owner USERNAME. This succeeds only while no owner exists and only if the target is already an admin. - Transfer (after that). Once an owner exists, ownership moves only through the ownership-transfer flow (
POST /v1/account/owner/transfer), which hands the owner role to another admin. Trying to bootstrap again is rejected because an owner already exists.
Last-owner protection
There is always exactly one owner. The last owner cannot be demoted and cannot be deleted — both are blocked at the server. To step down, an owner transfers ownership to another admin first; the transfer itself performs the swap.
Custom roles (RBAC)
Beside the coarse role, an owner can define custom roles — named bundles of capabilities — and assign them to principals to delegate a slice of admin power without granting full admin.
- Capabilities are either system-wide (empty scope) or topic-scoped (a topic name or
*pattern, matched with the same wildcard rule as topic ACLs). System capabilities includeusers.manage,acl.manage,groups.manage,branding.manage,tours.manage,approvals.manage,server.view,topics.acl.viewandtopics.protect.manage. Topic-scoped ones aretopic.acl.manage,topic.protect.manageandtopic.acl.view— e.g. authority overteam-*only. - Assignment targets a user or a whole group (in the
@g:<group>form), so a role can be handed to every member of a group at once. - Role management is owner-only. Role CRUD and assignment are the anti-self-escalation guard, so only the owner sees the Roles card and can use it (or the
ntfy roleCLI). There is no delegable "manage roles" capability — it stays with the owner.
See MokoNtfy CLI — groups, roles & protected topics for the exact ntfy role syntax.
How it composes with groups and protected topics
For a user (admin/owner bypass all of this), a request on a topic is resolved by the real authorization engine in this shape:
- Groups are additive. A group grant applies to every member; a user's effective topic permission is the union of their groups' grants. Group grants are read/write/read-write only — a group deny is not allowed.
- Per-user grants win. A user's own explicit grant (including a per-user
deny) always takes precedence over any group grant — that's how you subtract access that a group would otherwise give. - Protected topics require an explicit grant. A topic marked protected is no longer reachable through the fall-through Everyone grant or the server's default access; a matching user or group grant is required. Owners, admins and the topic's reservation owner still retain access.
- Custom roles don't grant topic publish/subscribe access; they grant management capabilities (e.g. the ability to manage a topic's ACL or protect it). Access to send/receive on a topic still comes from the ACL grants above.
The admin Access preview resolves all of this for you: pick a user (or an anonymous visitor) and a topic and it reports read/write allowed or denied using the same engine.