Auth Policy
A near-universal access-control modifier you attach to the 47 element types the runtime's unified attach graph considers compatible (app, automation, board, circle, claude-code, codex, csharp, diagram, discord, document, email, external-agent, facebook, files, fortnox, github, go-fn, graph, hitl, http, instagram, javascript, lab, linkedin, matrix, mattermost, open-code, phone-number, planning-board, python, recruitment-board, rocketchat, ruby, rust-fn, sales-board, slack, spa, sql, ssr, teams, three-d, timeseries, triformer, twitter, vector, view, websocket) so one place declares who may call them — accepting the chosen authentication methods and the authorization rules, and rejecting a request with a 401 or 403 before it ever reaches your code. (On io elements it attaches mainly for cascade hygiene; the live 401/403 gate is on the actor, frontend, and API surfaces.)
Working with it
Selecting a Auth Policy reveals its settings in the properties panel; it has no dedicated full-screen workbench.
How it appears
The same element type rendered as a definition, a circle instance, and a live workspace card.
When to use / not
When to use
- Protecting a public-facing endpoint, app, or action so callers must present valid credentials before the request runs.
- Centralising one set of auth rules and reusing it across many elements, instead of re-declaring authentication on each one.
- Enforcing role- or scope-based access — denying authenticated callers who lack the required role or permission.
- Adding a restrictive auth requirement to a scope where the strictest policy should win over anything inherited.
When not to use
- Minting the bearer tokens or keys that callers authenticate *with* — that is the api-token element; auth-policy only checks credentials, it does not issue them.
- Brokering a third-party login / OAuth grant flow to obtain access tokens — reach for the oauth modifier; auth-policy validates the credential a request already carries.
- Tenant isolation itself — circles are the airtight boundary; auth-policy guards entry to elements inside a circle, it is not the boundary.
Topology
Attaches to another element as a modifier, shaping that element's behaviour rather than running on its own.
Properties
authenticationobject- Authentication configuration
scopeobject- Policy scope
sessionobject- Session configuration
tokenobject- Token lifecycle configuration. Declares WHEN a bearer/api_key token should be proactively refreshed and WHERE to refresh it. Distinct from `session.*`, which governs session-cookie lifetime only and does not apply to bearer or api_key tokens. Advisory: the `evaluate` operation is a simulation endpoint and reports the configured lifecycle back in its response, but performs no outbound refresh call. Live refresh-and-retry enforcement is tracked separately (IMPROVE-381); outbound OAuth credential refresh already has its own home and is not duplicated here.
rulesarray- Top-level authorization rules (allow/deny per action+resource). Same as authorization.rules.
groupsarray- Required groups for access. Same as authorization.groups.
Capabilities
Defined for this element
- Auth
- Evaluate
- Observe
Operations
- attachPOST
- deleteDELETE
- detachPOST
- disablePOST
- enablePOST
- evaluatePOST
- getGET
- get_attached_modifiersGET
- intentionGET
- list_attachmentsGET
- readmeGET
- readme_updatePOST
- schemaGET
- updatePATCH
Ports
Inputs
- authenticationconfig
- authorizationconfig
- scopeconfig
Errors / when it fails
- Auth policy should define roles and/or permissions
- Fails unless:
len(authorization.roles) > 0 or len(authorization.permissions) > 0
Validation rules
- Policy does not require authentication - ensure this is intentional
- Policy grants admin role - ensure proper authorization checks
Auth Policy (auth-policy)
Category: modifiers | Form: | Symbol: Ay
Define authentication requirements and access rules
Defines authentication and authorization requirements for attached elements. Cascade strategy: restrictive — when inherited and local policies conflict, the stricter policy wins. Evaluation order 50 (early in the middleware chain, after CORS at 5). Attaches to the near-universal set of action, agent, app, automation, board, frontend, integration, and integration-connector element types whose target contracts opt in (47 element types in the runtime’s unified attach graph: app, automation, board, circle, claude-code, codex, csharp, diagram, discord, document, email, external-agent, facebook, files, fortnox, github, go-fn, graph, hitl, http, instagram, javascript, lab, linkedin, matrix, mattermost, open-code, phone-number, planning-board, python, recruitment-board, rocketchat, ruby, rust-fn, sales-board, slack, spa, sql, ssr, teams, three-d, timeseries, triformer, twitter, vector, view, websocket). Fails with HTTP 401 when auth is required but not provided, or 403 when credentials are present but insufficient. Spec supports
authentication.methodsarray (first entry is the required method, default “bearer”) andauthorization.type(default “rbac”). Theevaluateoperation checks credentials against the policy and returns allowed/denied. Use auth-policy for access control; use api-token for creating bearer tokens to authenticate with. Common mistake: not attaching auth-policy to public-facing elements. For io elements (inbound HTTP, etc.), the policy attaches for cascade hygiene; credential validation runs through the io element’s nativespec.authconfiguration (bearer/api_key/ hmac/basic). The full machine-token authorization mode is tracked in IMPROVE-381.
Guide
Overview
An auth-policy is a modifier you attach to an element to tighten who may reach it: require authentication, require MFA, restrict to particular roles, or narrow the policy to certain paths and methods.
What it can and cannot do
It can only TIGHTEN access. It can never widen it.
check_auth_policy (physics/src/runtime/modifier_evaluator.rs) runs after
the platform’s own check_authorization, and is structurally additive: every
arm returns either Ok(()) or an error. There is no path through it that
grants access. So attaching an auth-policy:
- cannot make an element public,
- cannot turn a 401 into a 200,
- cannot fix a
422 VISIBILITY_NOT_ALLOWED.
If you are trying to let anonymous visitors reach an element, auth-policy
is the wrong tool — put an io/http gateway in front of it instead. See
Public pages that show live data.
Cascade is restrictive: when an inherited policy and a local one disagree, the stricter one wins, so tightening a parent can never be silently loosened by a child. Evaluation order is 50.
Where it is enforced, and where it is not
Enforced on the operation-dispatch and element-execution rails — /ops/*
invocations and WebSocket open. It is not the credential check for io
inbound (receive ops authenticate against the io element’s own spec.auth),
and it does not gate frontend /live serving, where visible_to is the
only gate. Attaching a policy to a visible_to: everyone SPA changes nothing
about who can load that page.
Configuration
The schema is properties.yaml. The examples below are lifted from its
examples: block, so they are schema-valid by construction.
Require authentication, allow one role
authentication:
required: true
methods: [bearer]
authorization:
type: rbac
rules:
- effect: allow
role: admin
action: "*"
resource: "*"
Top-level rules alias
rules and groups may be written at the top level instead of nested under
authorization. Pick one shape, don’t mix them — mixing is the most
common first-attempt 422.
rules:
- effect: allow
role: admin
action: "*"
resource: "*"
With token refresh
authentication:
required: true
methods: [bearer]
token:
refresh_endpoint: "https://auth.example.com/oauth/token"
refresh_before_seconds: 30
refresh_skew_seconds: 10
Fields
Top-level: authentication, authorization, scope, session, token,
plus the rules / groups aliases. Nothing is required.
authentication.required defaults to true — and an omitted
authentication: block inherits that default rather than inverting it. (It
used to invert: a policy written with only authorization.rules required no
authentication and, because of an early return, skipped every role, group,
scope and rule check below it. A deny-all rule on such a policy denied
nothing.)
authentication.methods accepts api_key, bearer, oauth2, session,
saml, oidc. The first entry is the required method; the default is
bearer.
authorization carries two DISTINCT rule shapes — do not mix their fields.
RBAC rules[] take {effect, action, resource, role}. ABAC conditions[]
take {attribute, operator, value}. Putting ABAC keys inside a rules[]
entry is the other common 422.
Related
api-token— mints the bearer credentials you authenticate with. auth-policy guards the door; api-token makes the key.- Failure statuses: 401 when authentication is required but absent, 403 when a credential is present but insufficient.
Error Recovery
| Error | Recovery guidance | Next actions |
|---|---|---|
validation | Auth-policy accepts two schema shapes: nested (authorization.rules) and a top-level rules alias. Pick one, don’t mix. |
Capabilities
- require-auth: Enforce authentication
- roles: Role-based access
- permissions: Permission-based access
- scopes: OAuth scope requirements
Properties
| Property | Type | Default | Description |
|---|---|---|---|
authentication | object | — | Authentication configuration |
authorization | object | — | Authorization config. Two DISTINCT rule shapes live here — do NOT mix their fields. RBAC rules[] take {effect, action, resource, role} (e.g. {effect: ‘allow’, action: ‘read’, resource: ‘/api/docs/*’, role: ‘editor’}). ABAC conditions[] take {attribute, operator, value} (e.g. {attribute: ‘department’, operator: ‘eq’, value: ‘finance’}). Putting ABAC attribute/operator/value keys inside a rules[] entry is the #1 first-attempt 422 (a rule’s allowed properties are only action/effect/resource/role). Set type (rbac | abac | acl) to signal intent. |
scope | object | — | Policy scope |
session | object | — | Session configuration |
token | object | — | Token lifecycle configuration. Declares WHEN a bearer/api_key token should be proactively refreshed and WHERE to refresh it. Distinct from session.*, which governs session-cookie lifetime only and does not apply to bearer or api_key tokens. Advisory: the evaluate operation is a simulation endpoint and reports the configured lifecycle back in its response, but performs no outbound refresh call. Live refresh-and-retry enforcement is tracked separately (IMPROVE-381); outbound OAuth credential refresh already has its own home and is not duplicated here. |
rules | array | — | Top-level authorization rules (allow/deny per action+resource). Same as authorization.rules. |
groups | array | — | Required groups for access. Same as authorization.groups. |
Operations
attach
Post /ops/attach | Auth: Read
Attach this modifier to a target element
Attaches this modifier to a target element. The target_id must be a UUID of an existing element that supports this modifier type (check applies_to in definition.yaml). Priority controls evaluation order when multiple modifiers of the same type are attached — lower priority runs first. The attachment is stored in element_modifiers table. Cascade resolution runs at bond-time to merge this modifier into the target’s resolved config. Common mistake: attaching to an incompatible element type — check topology rules first.
delete
Delete /ops/delete | Auth: Admin
Delete element (soft delete)
Soft delete — sets state to ‘deleted’ but retains the record. Cannot delete elements that have children (has_no_bond precondition) or active runs. Requires admin auth and confirmation.
detach
Post /ops/detach | Auth: Read
Detach this modifier from a target element
Removes this modifier from a target element. Requires the target_id. Pervasive modifiers (audit, policy) can only be detached at the level they were originally attached — inherited pervasive modifiers cannot be detached by child elements. After detach, cascade resolution re-runs to remove this modifier’s effect from the resolved config.
disable
Post /ops/disable | Auth: Admin
Disable element (hides and prevents use)
Idempotent — safe to call on already-disabled elements. Optionally pass a reason string. Disabled elements cannot be invoked or executed. Inverse of enable.
enable
Post /ops/enable | Auth: Admin
Enable element (makes usable and visible)
Idempotent — safe to call on already-enabled elements. Transitions element to ready/enabled state. Cannot enable deleted elements. Inverse of disable.
evaluate
Post /ops/evaluate | Auth: Read
Evaluate authentication policy
Tests credentials against this policy. Accepts flat fields (role, action, token), nested objects (subject.role, request.action), or context paths (context.role, context.action). Reads spec.authentication.methods[0] (default “bearer”) and spec.authorization.type (default “rbac”). Returns allowed (bool), denied_reasons, and policy details. Configure spec.authorization.roles and spec.authorization.permissions to enforce access control.
get
Get /ops/get | Auth: Read
Get element details
Element is already resolved by the routing layer — this returns the cached element, not a fresh DB query. Use the path /api/{circle}/{slug} to address elements.
get_attached_modifiers
Get /ops/attached/{target_id} | Auth: Read
Get all modifiers attached to a target element
Lists all modifiers attached to a specific target element, including modifier_id, type, subcategory, and priority. Useful for debugging cascade resolution or understanding which policies apply to an element before invoking it. Each entry also exposes attachment_id (the element_modifiers row id; same value as modifier_id, which is kept as a deprecated alias) and modifier_uuid (the source modifier element’s own UUID, omitted when the named source element is absent or deleted). During triage, use modifier_uuid to identify the bound modifier element, not modifier_id.
intention
Get /ops/intention | Auth: Read
Get element intention with full inheritance chain
Returns three levels: direct (this element’s intention), inherited (from category and root), and resolved (final merged intention). Useful for understanding an element’s purpose in context of its hierarchy.
list_attachments
Get /ops/targets | Auth: Read
List all elements this modifier is attached to
Returns all target elements where this modifier is currently applied. Shows target_id, target_type, priority, and cascade_policy.
readme
Get /ops/readme | Auth: Read
Get element README.md content
Reads README.md from the element’s git repository. Returns empty content (not an error) if no README exists. Always returns markdown format.
readme_update
Post /ops/readme_update | Auth: Write
Update element README.md content
Creates or overwrites README.md in the element’s git repo. Commits to the draft branch. Content must be provided as a markdown string.
schema
Get /ops/schema | Auth: Read
Get element input/output schema (MCP tools/list compatible)
Returns type-level port schemas from the TypeRegistry — not instance-specific overrides. Includes direction (input/output), required flag, and JSON schema per port. Useful for understanding what data an element accepts and produces.
update
Patch /ops/update | Auth: Write
Update element
Partial update — send only the fields you want to change.
spec,name, andintentionare all independently optional.specMUST be a JSON object when present; deep-merged into the existing spec by default. Empty{"spec":{}}preserves existing spec content but still records a new version (no-op for content, not for version state). To clear/replace the entire spec wholesale send{"spec":{...},"deep":false}. List-typed spec fields use replace semantics (the patch list replaces the existing list, no array merging). Coordinates Git + DB writes. Slug cannot be changed after creation.
Error Codes
| Code | Class | Retryable | Description |
|---|---|---|---|
AUTH_REQUIRED | auth | no | Authentication required |
AUTH_INVALID_TOKEN | auth | no | Invalid or expired token |
AUTH_INSUFFICIENT_PERMISSIONS | auth | no | Missing required permissions |
AUTH_INSUFFICIENT_ROLES | auth | no | Missing required roles |
Lifecycle / runtime
Defined for this element
Execution model: sync
Observability
Defined for this element
Metrics
- evaluation_count
- rejection_count
Events
- auth-policy.evaluated
- auth-policy.rejected
Pricing / cost
Platform default
Operation costs
- create: free
- update: free
- delete: free
- get: free
- list: free
- invoke: 10000 micro-AU
- tool_use: free
Set it up
- Require Authenticationstring
- Auth Methodsstring