Policies and Conditions
Policies let you express authorization rules that are broader or more conditional than a direct role permission.
Use policies when:
- The rule depends on runtime context.
- The same rule should attach to multiple entities.
- You want to author statements in Cedar and compile them into the RBAC engine.
- You need linting, history, rollback, or delete impact around policy changes.
JSON statements
Create a policy with JSON statements:
POST /policies
Content-Type: application/json
{
"id": "policy-own-profile",
"statements": [
{
"effect": "can",
"actions": ["read", "write"],
"resources": ["profile/*"],
"when": {
"resource.id": { "eq": { "$ref": "principal.id" } }
}
}
]
}Attach the policy to a role:
POST /policies/policy-document-owner/attachments
Content-Type: application/json
{
"entityType": "ROLE",
"entityId": "role-member"
}Conditions
Conditions evaluate against facts with a known source (full table in docs/platform/CONTEXT-KEYS.md):
- Engine facts —
resource.type,resource.id,resource.scope,principal.id,subject.tenant, and the server clocktime.hour/time.dayOfWeek(UTC,0= Sunday). - Request facts —
request.mfa,request.mfaAge,request.ip, derived by the server from the verified token and the deployment's client-IP source. Never settable by a caller. - Resource attributes —
resource.<attr>for attributes your catalog manifest declares on the type (requiredor optional, typedstring,number,boolean,string[]orprincipalRef). Your backend supplies them as an attestation on the broker or attested check routes; end users never can. - Trusted context —
context.<name>for products that set"trustedContext": trueand declare a typedcontextSchema(e.g.clientIpof typeip); accepted only from service credentials.
Read an optional attribute only behind an exists guard in the same $and (a required one needs no guard) — writes
that read an optional attribute unguarded are refused:
{ "$and": [ { "resource.pinned": { "exists": true } }, { "resource.pinned": { "eq": true } } ] }An owner-only rule reads an attested attribute:
{ "resource.createdBy": { "eq": "${subject.id}" } }Supported condition patterns include:
- Equality:
eq,notEq - Lists:
in,contains,containsAll,containsAny - Comparison:
gt,gte,lt,lte - Strings and patterns:
like - Presence:
exists - Network checks:
cidr(IPv4 and IPv6; an address never matches a range of the other family) - Logic:
$and,$or,$not - Runtime references:
$ref
Office hours on engine facts only:
{
"$and": [
{ "time.dayOfWeek": { "in": [1, 2, 3, 4, 5] } },
{ "time.hour": { "gte": 8 } },
{ "time.hour": { "lt": 18 } }
]
}A check that reaches a rule needing a fact it doesn't have is denied without evaluating it (attestation_required,
request_fact_unavailable, context_required, with the missing keys). A malformed condition never allows and always
denies.
Attestations are the entity snapshot. An omitted optional attribute (or null) is absent; every required attribute
must be present. In JavaScript, undefined is dropped by JSON.stringify, so an undefined value is an omitted
attribute, not null. Declare security-relevant facts (classification, author) as required.
Rollout order. Deploy the attesters that send a new required attribute before catalog apply makes it
required; otherwise their checks fail validation.
Cedar-authored policies
Policies can also be created with Cedar source:
{
"id": "policy-expense-approval",
"cedar": "permit (principal, action == Action::\"approve\", resource == Resource::\"expenses\") when { resource.amount < 5000 };"
}SaaSLayer Permissions compiles Cedar into JSON statements at write time. The hot permission-check path still uses the materialized permission document.
Use Cedar when your team prefers a policy language. Use JSON statements when your product needs direct control over the generated rules.
Policy lifecycle
Policy endpoints support:
- Create, list, update, and delete
- History
- Rollback
- Attachments
- Linting
- Delete impact
- Dry-run behavior where supported
Before changing a widely attached policy, inspect its attachments and preview impact. A single policy update can affect many principals.
Practical guidance
- Keep simple permissions on roles.
- Put conditional logic in policies.
- Prefer positive rules plus a small number of hard denies.
- Declare the attributes your rules read in the catalog manifest, and attest them from your backend.
- Test policy behavior with both allowed and denied examples.
- Use explain mode during policy rollout.