Members & permissions

How CMS access is authorized — the cms permission catalog, per-site roles, and scoped invites.

Not verified yet

Norcube CMS doesn't run its own access-control system. Every CMS action is authorized by Norcube Auth's IAM, against a resource that is either your whole organization or one specific site. This page is the authoritative list of what each permission gates, the roles you can hand out, and how you invite people to a single site.

How CMS access works

Authorization is delegated entirely to IAM. The CMS API carries no role logic of its own — it only declares, per route, which action it requires and which resource that action applies to. Two resource shapes exist:

Resource ARNScope
cms:org:<orgID>Org-level actions (list / create sites)
cms:site:<siteID>Everything under one site

Every authenticated request carries an access-token JWT minted by Norcube Auth. The CMS rejects any token whose audience isn't cms-api, even if the signature is valid — so a token scoped to another product (say, Backup) can't be replayed against the CMS. The token also carries your user id and organization id, which scope the query underneath the permission check.

On each /sites/:id/... request the CMS asks IAM a single question: "is this user allowed <action> on cms:site:<id>?" A denial is a 403; a missing or invalid identity is a 401. The check is unconditional in production. There is no way to reach a mutating endpoint without holding the matching permission.

The permission catalog

These are the exact cms:* actions. The server gates one action per route; the names here match the IAM action ids verbatim.

Sites

ActionResourceGates
cms:ListSitesorgList the sites in your organization
cms:CreateSiteorgCreate a new site
cms:GetSitesiteRead one site (and warm its clone)
cms:UpdateSitesiteRename / re-slug, connect git, sync
cms:DeleteSitesiteDelete a site

cms:GetSite also backs read-side helpers — the dashboard summary, full-text search, clone warm-up, and per-user editor preferences. cms:UpdateSite covers connecting the git repo and the manual "Pull from git" sync.

Content

ActionResourceGates
cms:ListContentsiteBrowse the content tree
cms:GetContentsiteRead one file, its page history, field
history, diffs and point-in-time snapshots
cms:UpdateContentsiteWrite a file (Publish), and provision /
sync the live preview
cms:DeleteContentsiteDelete a content file

Drafts

ActionResourceGates
cms:GetDraftsiteRead the staging draft + the drafts index
cms:UpdateDraftsiteSave / clear an in-progress editor draft

Saving in the editor is a draft write (cms:UpdateDraft); Publish is a content write (cms:UpdateContent).

Config & schema

ActionResourceGates
cms:GetConfigsiteRead the merged schema config
cms:UpdateConfigsiteWrite the single-file config; AI config
generation
cms:GetSchemasiteRead a per-file schema (config.yml, a
collection, or a block)
cms:UpdateSchemasiteInit / write / delete a schema file, and
AI block generation

Media

ActionResourceGates
cms:ListMediasiteList / search media, read declared
storages, mint signed preview URLs
cms:UploadMediasiteUpload a file into a storage
cms:ManageMediasiteDelete, rename / move, create folders

AI

ActionResourceGates
cms:UseAIsiteThe AI Assistant chat, apply / reject /
undo proposals, and the AI-generated site
profile

Discussion

ActionResourceGates
cms:ListDiscussionsiteRead a page thread + unread counts
cms:PostDiscussionsitePost a message; mark a thread read
cms:ManageDiscussionsiteEdit / delete a message

Editing or deleting also requires you to be the message's original author — that's an additional server-side check on top of cms:ManageDiscussion.

Activity & members

ActionResourceGates
cms:ListActivitysiteThe activity feed + live event stream
cms:InviteMembersiteDelegate CMS access to a site

Roles

Three per-site roles ship as system policies. They define an action set only — the site they apply to is bound per grant, at invite time.

RoleAction set
viewercms:Get*, cms:List* — read-only
editorviewer plus content, drafts, config, media, discussion and
AI writes, and cms:UpdateSite. No schema edits; no create
or delete of sites.
admincms:* — every CMS action on the site

The editor set is exactly: cms:Get*, cms:List*, cms:UpdateContent, cms:DeleteContent, cms:UpdateDraft, cms:UpdateConfig, cms:UploadMedia, cms:ManageMedia, cms:PostDiscussion, cms:ManageDiscussion, cms:UpdateSite, cms:UseAI. Note editors can edit and delete content and update site settings, but cannot touch schema or delete the site.

Above these sits the organization Owner policy (org:owner), which allows every action on every resource across all Norcube products — so an owner always has full CMS access to every site.

Roles aren't a fixed menu. A site invite grants an inline IAM policy, so anyone with the org-level auth:CreatePolicy right can build a custom policy (any subset of cms:* actions) and hand it out from the global IAM pages. The three named roles are the common presets, not the only options.

Inviting members to a site

The per-site Members page (CMS → your site → Members) lists everyone in the org who holds a CMS policy, plus pending invitations. The Invite button is gated on cms:InviteMember for that site — if you can't delegate access, you don't see it.

An invite is scoped to one site. You pick an email, a role (viewer / editor / admin), and an optional note that lands in the email. Under the hood the invitation grants two statements:

  • cms:ListSites on * — so the invitee's dashboard can load the site switcher. The list is still filtered server-side, so they only ever see the one site.
  • the role's actions scoped to cms:site:<id> — the real grant.

Invitations are email-bound. The invitee gets a one-time accept link; on accept they join your organization with access to only that site and nothing else. The invite also carries product context (cms plus the site name) so the email and accept page name the site instead of a generic "join this org."

You can never hand out access you don't hold yourself. IAM enforces anti-escalation: every action and resource in a grant must already be allowed to you, and you must hold the delegation right for each service the grant touches. A CMS-only collaborator can't mint a grant for any other product.

How the UI reflects permissions

The dashboard hides or disables controls you can't use. It reads your capabilities from Norcube Auth's self-scoped GET /iam/me/permissions?resource=cms:site:<id> endpoint and gates each control on the matching action:

ControlRequired action
New / edit page, Publishcms:UpdateContent
Delete pagecms:DeleteContent
Save draftcms:UpdateDraft
Edit schemacms:UpdateSchema
Upload mediacms:UploadMedia
Delete / rename mediacms:ManageMedia
Delete site (settings)cms:DeleteSite
Edit site settingscms:UpdateSite
Config generation / AIcms:UpdateConfig /
cms:UseAI
Invite to sitecms:InviteMember

This is defence-in-UX, not the gate. The capability read never widens access — it only mirrors what the server would allow. The CMS API authorizes every request independently, so a hidden button being forced open still gets a 403. While capabilities are still loading the UI is optimistic (controls show) to avoid flicker for owners and admins; the server remains the real guard.

What's not there yet

  • No role management surface on the member row. Changing someone's level means detaching the policy and re-inviting, or editing the IAM policy directly. There's no inline "promote to admin" control.
  • No field- or collection-level permissions. The finest grain is one site. Within a site, access is all-or-nothing per action — you can't scope someone to a single collection or folder.
  • No per-site audit log in the CMS itself. The Activity feed (cms:ListActivity) shows what changed, not an IAM access trail. IAM audit logs live in Norcube Auth.

Where to next

On this page