> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.cessy.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.cessy.ai/_mcp/server.

# Permissions

> Model Cessy roles, attributes, principals, command execution rules, and projection read rules explicitly in the app.

Permissions define who may act and who may read. They belong in the model, not only in custom page code or external clients.

## Building blocks

| Concept               | Meaning                                                                                     |
| --------------------- | ------------------------------------------------------------------------------------------- |
| Principal             | The user, service, or agent identity making the request.                                    |
| Role                  | Named business authority such as `Admin`, `Manager`, or `SupportAgent`.                     |
| Attribute             | Contextual property used for access decisions, such as team, region, account, or ownership. |
| Command permission    | Rule that allows or denies command execution.                                               |
| Projection permission | Rule that allows or denies reading projection data.                                         |

## Roleless Runtime API keys

Runtime API keys can be created before an app defines custom roles. Leave the
role list empty to create an authenticated, least-privilege API-key principal
with `roles: []`. Cessy does not inject the built-in `user` role, an admin role,
or a custom fallback role.

The existing opt-in authorization model still applies: Runtime behavior without
`authRules` remains available, while a rule that requires a role denies the key
until that matching role is assigned. Adding roles to the app later does not
silently change an existing roleless key.

## Command permissions

Command permissions protect business decisions. Check them before publish when a new command is added or an existing command changes meaning.

## Projection permissions

Projection permissions protect read data. A user who cannot execute a command may still be allowed to read a projection, or the reverse. Model both explicitly.

## Auth-rule composition

Multiple `authRules` on the same command, projection, page, or exposed adapter
operation are OR-combined: any matching expression grants access. Conditions
that must all hold belong in one expression. For example, use
`"'knowledge-user' in $principal.roles && $principal.attr.suspended != true"`,
not two array entries that would allow the role **or** any non-suspended
principal.

## External principal assertions and effective access

A Custom Page adapter principal assertion authenticates the server-resolved
principal to an external service. Its verified `sub` is identity, not an
authorization grant. The assertion intentionally omits roles, attributes,
groups, and application-specific tags.

When the downstream needs current fine-grained access, model an app-owned
`EffectiveKnowledgeAccess` projection keyed by principal ID:

```json
{
  "id": "<principal-id>",
  "active": true,
  "allowedTags": ["support", "product-a"],
  "accessVersion": 7
}
```

Create a dedicated Runtime API key with a narrow role such as
`knowledge-access-reader`. Add one projection rule that permits that role and
do not grant it on unrelated projections. The external service verifies the
assertion first, then uses only its `sub` to call:

```http
GET /api/rest/{tenantId}/{appId}/projections/EffectiveKnowledgeAccess/{url-encoded-sub}
Authorization: Bearer <dedicated-runtime-api-key>
```

For signed `runtime_source = workspace:<workspaceId>`, append
`?workspaceId=<url-encoded-workspaceId>` (or send the equivalent runtime-source
header); omit the selector for `production`. Derive it only from the verified
claim. The key remains in the external service and never enters Custom Page
code. Missing, inactive, malformed, or empty access, a 404, an
authorization/read error, or a source mismatch all deny. Never fall back to
browser-provided identity or tags.

Keep three authorities separate: the human/Page principal, the dedicated
Runtime API-key principal that may read only this projection, and the HS256
signing key. HS256 gives the verifier co-signing power, so isolate that shared
key per adapter trust domain/audience and environment and never reuse it as the
Runtime API key. See [Adapters](/extend-the-app/adapters) for the verifier contract and
[Build Custom Pages](/build-a-frontend) for setup and tampering tests.

## Agents

Runtime agents need scoped authority. Give an agent only the command and projection access required for its job, and make user-visible actions auditable in Activity or channels.

App agents are controlled by app-level Agent Scope Profiles in addition to command and projection auth rules. Runtime MCP-only agents default to the built-in `runtime-operator` profile, which allows Runtime MCP workspace and production commands plus production projection reads. Design-capable agents default to `safe-builder`, and platform-managed agents default to `platform-admin`.

A profile can allow Workspace authoring while denying Production promotion, allow Workspace command execution while denying Production command execution, and separately allow or deny Production projection/log/debug reads.

Admins can inspect effective agent access and manage versioned scope profiles in Design → Security → Agent Scopes. Built-in profiles can be assigned directly, so an existing Runtime MCP-only agent pinned to `safe-builder` can be repaired by assigning `runtime-operator`. Scope profile, assignment, and approval-policy changes are stored as Change Requests and follow the app's central approval policy.

Design MCP exposes Agent Scope discovery and proposal tools through the `agent-scopes` capability group. For a builder that may edit Workspaces and ChangeSets but may not promote to Production, omit `promote` from the ChangeSet action list, leave promotion environments empty, and deny the promotion tools.

## File permissions

Durable Platform files persist one server-owned access rule. Browser uploads
default to the authenticated `principal`; callers cannot choose another
principal. `projection-document` delegates to the referenced projection's
document authorization. The broad `app` compatibility scope must be selected
explicitly and applies to every authenticated operator with app access.

Policy file writes must choose one of those scopes explicitly. File metadata,
roles, tags, MIME types, filenames, request fields, and copied URLs are not
authorization inputs. Runtime MCP and browser `GET`/`HEAD` evaluate the same
tenant, app, runtime-source, and stored-scope contract. Unknown and known-denied
objects both return a non-revealing not-found response.

Native chat uploads are uploader-only until the uploader commits the exact
stored attachment in a channel message. Other humans additionally need current
membership in that exact channel; agents use the corresponding exact channel
participation and message-proof boundary. Standalone chat attachments remain
uploader-only.

## Verification

Test at least one allowed actor and one denied actor for sensitive commands,
projections, and files. File tests should exercise both `GET` and `HEAD`, an
unknown id, two principals, another tenant, and channel membership where chat
attachments are involved. For assertion-backed adapters, use two authenticated
principals with disjoint effective-access documents and prove that forged
browser IDs, tags, and reserved headers cannot cross their access boundary.