Core Concepts
SaaSLayer Permissions combines role-based access control, attribute-based policy conditions, relationship-aware hierarchy, and direct resource grants. The model is broad, but the core pieces are small.
Principals
A principal is something that can receive permissions.
Supported principal types include:
USERAGENTSERVICE_ACCOUNT
Users usually represent humans. Agents and service accounts represent automated actors, integrations, or delegated workflows.
Agent and service account ids and names
Agents and service accounts get a server-generated, immutable id (agt_… for agents, sa_… for service accounts). You choose a name, which is unique per owner and principal type and becomes reusable once the principal is deleted:
POST /principals/serviceAccount
Idempotency-Key: deploy-bot-v1
{ "name": "deploy-bot", "ownerType": "org", "ownerId": "org_acme" }201returns the new principal with its generatedid. Store theidwherever you reference the principal (grants, audit, your own data such asnote.createdBy).- Retrying with the same
Idempotency-Key(default: a hash of the payload) and the same payload returns200with the existing principal. - The same name under the same owner with a different key or payload returns
409 NameTaken. - Passing an
idin the body returns400.
Resolve a name to its principal with GET /principals/serviceAccount?name=deploy-bot&ownerType=org&ownerId=org_acme.
Users keep the id you give them. Creating a user never overwrites one: a repeat create whose fields already match is a
no-op, anything else is 409 Conflict. During a maintenance cutover every principal create answers
503 PrincipalCreationPaused with a Retry-After header; retry after that many seconds.
Every decision is keyed by the principal's type as well as its id, so an agent never inherits a user's permissions, grants or orgs even when their ids are equal.
DELETE /principals/{type}/{id} removes the principal together with its role assignments, direct grants, memberships, sessions, delegated grants, standing delegations it owns or grants through, API keys, auth methods and cached permission documents, and frees its name. Re-creating the same name produces a new id, so nothing that referenced the old principal applies to the new one. A principal that still owns other principals returns 409 until they are transferred or deleted.
Authenticating principals (USER, AGENT, SERVICE_ACCOUNT) can also act for another principal via agent delegation, and can authenticate themselves through external identity providers via federated principal auth instead of long-lived API keys.
Organizations, workspaces, and groups
The hierarchy gives permissions a business context:
Organization
Workspace
GroupUse organizations for customer accounts. Use workspaces (/workspaces) for subdivisions inside an organization, such as environments or product boundaries. Use groups for teams or collections inside a workspace.
Membership and role assignment are separate. A user can belong to a workspace without having any useful permissions there.
Roles
A role is a named bundle of permissions.
Example permissions:
[
{ "effect": "can", "action": "read", "resource": "invoice", "service": "billing" },
{ "effect": "can", "action": "approve", "resource": "invoice", "service": "billing" },
{ "effect": "deny", "action": "delete", "resource": "invoice", "service": "billing" }
]Roles can be assigned globally or at a scope such as a workspace. Roles can also inherit from parent roles.
Policies
Policies are reusable statement bundles that can attach to users, roles, organizations, workspaces, or groups.
Use policies when a rule is more expressive than a simple role permission, or when you want to attach the same conditional logic in multiple places.
Policies can be written as JSON statements or authored in Cedar and compiled into SaaSLayer Permissions statements at write time.
Resources
Resources are the things your application protects: invoices, devices, documents, projects, API routes, tools, or anything else.
Simple resource strings work:
device
invoice
document/doc-123For cross-service resource identity, use XRNs:
xrn:saas:billing:us-west-1:tenant-acme-prod:invoice/inv-123Actions
Actions are verbs in your product domain:
read
write
delete
approve
export
inviteUse stable product actions instead of HTTP verbs. For example, approve is clearer than POST.
Scopes
A scope limits where a permission applies.
Common scopes:
- Workspace ID
- Organization ID
- Group ID
nullfor global permissions
When a permission check includes a scope, SaaSLayer Permissions evaluates global permissions plus permissions scoped to that value.
Denies
Deny rules override allows. If one matching permission says deny, access is denied even if another matching permission says can.
Use denies sparingly. They are useful for hard restrictions, compliance boundaries, and inherited roles where a child role must explicitly block a parent capability.
Permission boundaries
A permission boundary is a maximum-access ceiling. A role or principal might allow an action, but the boundary can still block it.
Use boundaries for administrative guardrails:
- Support users can read customer data but cannot delete it.
- Contractors can manage tickets but cannot export data.
- Service accounts can write events but cannot manage users.
Grants
Grants are direct resource shares. They are useful when role-based access does not naturally express a one-off share.
Example: a user does not have read on every document in a tenant, but someone shares document/doc-123 directly with them.
A grant names the grantee's type and id, the action, and the resource's scope, service, type and id — all required
except scope, which defaults to * (global). A grant answers only checks in its own service and scope, and a global
grant answers only checks with no scope. The caller must be allowed in the grant's scope and hold the permission it
grants. A grant is consulted only when no role or policy allowed or denied the check.
Materialized permission documents
SaaSLayer Permissions materializes effective permissions into a PERMISSIONS document per principal. Permission checks read that document and evaluate in memory.
That is why the hot path can be a single DynamoDB read. Writes may trigger rebuilds or invalidation, but reads stay fast.
Sessions
Three session shapes coexist:
| Kind | Subject acts as | When to use |
|---|---|---|
| Assumed-role session | A different role for a bounded window. | Support engineer temporarily assumes a customer-support role. |
| Direct principal session | The subject itself. | Workload authenticates via federated principal auth and acts as itself. |
| Delegated principal session | The subject, but actingFor another principal. | Agent acts on a user's behalf via agent delegation. |
All three are bearer-token sess_<jwt> formats and authorize through the same one-row-lookup hot path.