Skip to content

Permissions and Roles

What is this

How identity and access work in ComStack: three layers of identity, project roles, and application in MCP tools and REST endpoints.

How it works

Identity layers

There are three independent identity layers in parallel:

LayerPurpose
UserGlobal identity. One per real person, identified by Firebase Auth UID.
AccountLegal and billing entity. Owns projects.
Project MemberAccess per project with an assigned role.
Platform AdminGlobal access for the ComStack team: bypasses all project-level checks.

A single user can be a member of multiple projects across various accounts. Account membership and project membership are independent: being the account owner does not grant automatic project access.

Project roles

Three project roles stored in the member document:

RoleDescription
managerFull project access: content, settings, members, and all destructive operations.
editorIntended for content editing without destructive privileges. Currently not enforced: behaves the same as a generic member (see Implementation Gap below).
viewerIntended for read-only access. Currently not enforced: behaves the same as a generic member.

MCP tool capabilities matrix

CapabilitymanagerAny memberPlatform Admin
get-project-state, get-page-content, list-pages
create-page, update-page
delete-page, update-theme
publish, publish-confirm
connect-github, pull-and-publish, revert-publish
Template CRUD tools
whoami, list-my-projects, create-project, get-guide

tools/list is filtered based on the caller: those who are not manager do not see exclusive management tools. The filter result is cached for 30 seconds per user.

Implementation gap: editor/viewer not enforced

The API accepts editor and viewer role values, but the authentication layer only distinguishes between manager and “any member document exists.” Editor and viewer behave identically: both get non-destructive read/write access, just like any other member.

Do not rely on distinctions between editor and viewer for security.

When to use it

  • Check what a caller can do with a given role before creating a workflow.
  • Diagnose a 403 error in an MCP tool call (is the caller a manager?).
  • Understand what tools/list returns for different role levels.

Parameters / fields / inputs

How users are created:

  • First OAuth login: the user document is created automatically.
  • Added to a project by email: if a Firebase Auth user does not exist for that email, one is created.

How projects are created: the create-project MCP tool is the only way. The creator is automatically added as a manager.

How members are added: POST /api/projects/:projectId/members (requires manager). Accepts email, role (manager, editor, or viewer), and an optional display_name.

Example

A caller with the manager role calls publish: it succeeds. A caller with the editor role calls publish: it returns 403 Forbidden.

A caller without project membership calls list-my-projects: returns an empty list. create-project: succeeds (any registered user can create a project). get-project-state for a specific project: returns 403 (not a member).

Common errors

403 on publish or delete-page: the caller has the editor or viewer role, not manager. Update the member role to manager via PATCH /api/projects/:projectId/members/:uid.

403 on get-project-state: the caller is not a project member. Add them via POST /api/projects/:projectId/members.

403 on Template CRUD tools: these require Platform Admin access, not just project manager. Contact the ComStack team.

  • Authentication — how roles are checked in the middleware.
  • MCP Servertools/list filtering and the capabilities matrix in context.
  • Plans and Quotas — quota enforcement works alongside role checks.

Last updated: