The governance model

Roles, policies and conditions decide what any caller may do; approvals put a person in front of the steps you choose.

Everything Authoric does about access reduces to one sentence:

A principal holds roles. Roles carry policies. A policy grants actions on resources, optionally under conditions. Every request is checked against the policies of the principal making it, at the moment it happens.

There is no second mechanism and no bypass for internal callers. Your app's users, its API keys, its scheduled jobs and its AI agents are all governed by that sentence, and every decision lands in the same audit log. So does every change to it: creating, renaming or deleting a role or a policy, attaching a policy to a role, giving a role to a principal, and adding or changing a custom action, each with who made it and when.

Policies

A policy grants actions on resources. Policy keys read as resource:action:

KeyGrants
notes:read_listList rows in notes
notes:readRead one row of notes by uid
notes:createInsert into notes
orders:deleteDelete from orders
sdk:queryRun raw SQL from inside a handler

Every table you create arrives with the same five actions (create, read, read_list, update, delete), and none of them is reachable until a policy grants it. Custom actions and handler SDK calls have keys of their own.

A grant can carry conditions: only rows the caller owns, only an amount up to a ceiling, only certain values of an argument. "May refund" is a permission; "may refund up to $5,000" is a policy. The condition is evaluated by the server on every call, so no instruction, prompt or request body can talk its way past it.

Roles

A role is a named bundle of policies: support, billing-admin, read-only. You bind policies to roles and roles to principals. Principals never hold policies directly, which keeps "what can this caller do" answerable by looking at one place; the console shows each principal's Effective permissions.

Roles belong to an app. A role in one app has no meaning in another. Every app has built-in roles, including User, which every user of the app holds and which grants nothing on your tables until you assign a policy to it.

Checking happens per request

Authorization is resolved for each request from that request's own principal. It is not computed once at sign-in and carried in the token, and it is not held in shared state between requests. That is why a token can never widen its own reach: what a caller may do comes from its roles at the moment of the call, not from anything it sends. Revoke a policy and the next request is refused.

Approvals

Some steps deserve a person's decision even when the caller is allowed to take them. Two kinds of work can pause for one:

  • An agent's step. Every operation has a risk level: reads are low, creates and updates are moderate, deletes are high, and you can override any of them per table or action. A step above low pauses unless the agent is set to auto-approve actions.
  • A handler. Your own code can stop and ask, with sdk.awaitApproval, before it does something consequential.

The step is reached

The agent has decided to issue a refund, delete a record or publish a handler; or a handler has reached its approval point.

The work pauses

Nothing is executed. The run reports pending_approval, and the intended action, with its exact arguments, is recorded.

A person decides

The pending step appears in the console under Approvals (or App approvals in the app), with what it does, what the run was for, and what has already happened in it. The caller that raised a request can never approve it.

The run continues

On approval, the step executes and the run carries on from where it stopped. On rejection, nothing executes; the agent is told no, with your reason if you gave one, and continues without that step.

An API key can tighten this, forcing a person's approval even for an agent set to auto-approve, but nothing a caller sends can loosen it. A pause is a normal outcome, not an error: treat pending_approval as a state to wait on.

Where an agent's abilities come from

An agent has no tool list of its own. Its tools are derived from the policies on its roles. Grant refunds:create and creating a refund appears among its tools; revoke it and the tool is gone, for its runs, for direct tool calls and for any MCP client connected to it at once, because all three read the same derivation.

So governing an agent is the same work as governing a user, not a parallel system that has to be kept in step. And because the limits are policy, an agent cannot exceed its grant no matter what its instructions or its input say.

What's next

On this page