Available

Limit what an agent may do

Grant an AI agent a capability, set limits on the details of each action, and add project rules that deny an action or send it to a person.

An AI agent starts with no permissions. This guide shows you how to give an agent a permission, grant it a capability that limits the details of what it may do, and add rules that hold for the whole project.

How permissions, capabilities, limits and rules fit together

Four things decide what an agent may do.

  • A permission is an action on one kind of thing, such as transfer:accounts. An agent holds a permission the way a person does: through a role.
  • A capability names that permission on the agent itself, and can carry limits on it. The console shows a capability as a permission on the agent's Permissions tab.
  • A limit is a condition on the details of one action. It belongs to one capability on one agent: this agent may transfer, up to 5,000.
  • A rule applies across the project, to the agents and people it names. A rule can deny an action, or make it wait for a person to approve it. The console calls a rule a policy.

Each time the agent asks before acting, AuthFI checks the limits and the rules, and whether the agent holds the permission. The names of an agent's capabilities travel in its access token, in the capabilities and scope claims. The limits do not. They stay with AuthFI, so a changed limit applies to the agent's next call.

For the model behind this, see How agent sign-in works.

Before you begin

You need:

Give the agent the permission

An agent holds a permission the way a person does: through a role.

  1. In the console, open Identity > Roles & permissions and select the Permissions tab. Choose New permission, enter transfer as the Action and accounts as the Resource, and choose Add permission. The permission's key is transfer:accounts.
  2. On the Roles tab, choose New role, enter a Name such as Payments agent, and choose Create role. On the role's page, select transfer:accounts, choose Save changes, and confirm with Save.
  3. Choose Give this role, then An AI agent. Pick the agent and choose Give the role.

A permission is about one kind of thing. transfer:accounts covers the objects written account:…, such as account:4821.

Grant a capability

  1. In the console, open Identity > AI Agents and select the Agents tab.
  2. Open the agent, and select its Permissions tab.
  3. Under "What it may do on the platform", choose Grant a permission.
  4. Fill in the dialog, then choose Grant.
FieldEnter
PermissionThe capability, chosen from the project's permission catalogue
LimitsOptional. The limits on this capability, as JSON.
ReasonWhy the agent needs it. It is recorded with the grant.

Choose a permission whose name means something to the people who read it in an approval. This guide uses transfer:accounts.

The capability appears in the table on the Permissions tab, with its limits in the "Limited to" column.

Write the limits

In the Limits field, name each field of the action's details and the values it may take. The details are the context the agent sends when it asks before acting.

{
  "amount": { "max": 5000 },
  "currency": { "in": ["USD", "EUR"] },
  "region": { "not_in": ["sanctioned"] },
  "account_type": "business"
}
FormPasses when
{ "max": 5000 }The value is a number, 5000 or less
{ "min": 1 }The value is a number, 1 or more
{ "in": [...] }The value is one of the list
{ "not_in": [...] }The value is not in the list
A plain valueThe value is exactly that

The field shows {"amount": {"max": 2000}} as an example.

You can also set limits while you register an agent, in the "What it may do" step. There you choose Add a limit and pick an operator by name.

Operator in the register stepForm
at mostmax
at leastmin
is one ofin
is nevernot_in

Add a rule for the whole project

  1. In the console, open Security > Triage and select the Rules tab.
  2. Under "Policies", choose New policy.
  3. Enter a "Name", choose an "Effect", choose who the rule applies to in "Applies to", and choose Create draft.
  4. In the editor, choose Validate, then Enable, then Save.
EffectWhat it does
DenyThe action is denied. Nothing overrides a deny.
Require step-upThe action waits for a person to approve it

A rule names whom it applies to, an action, the things it applies to, and a condition on the action's details.

{
  "subjects": ["agent:*"],
  "relation": "transfer:accounts",
  "object": "account:*",
  "condition": { "field": "amount", "op": "gte", "value": 1000 }
}

agent:* is every agent, shown as Every agent in "Applies to". A condition compares a field with gte, gt, lte, lt, eq or ne.

With the effect "Require step-up", the rule above says that transfers of 1,000 or more need a person. It is one rule, and it holds for every agent you register from then on.

A new policy is marked "Draft". After you enable it, it is marked "Live".

Check that it works

Test a decision in the console first.

  1. Open Security > Authorization and select the Evaluate tab.
  2. Under "Would this be allowed?", enter the "Subject", the "Action" and "On what". For the example agent, the subject is agent:agt_7f3a9c21, the action is transfer:accounts and the object is account:4821.
  3. Choose Check.
The console answersMeaning
YesThe action is allowed
NoThe action is denied
Not on their ownThe action waits for a person

Then ask AuthFI to decide, as the agent does. A transfer of 100 is inside every limit, and below the 1,000 at which the rule asks for a person.

First bind a transaction token to the action. A transaction token names one action and its details, and lasts 60 seconds.

curl https://acme.authfi.io/apis/regional/v1/ai/auth/transaction-token \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "transfer:accounts",
    "resource": "account:4821",
    "context": { "amount": 100, "currency": "USD", "account_type": "business" }
  }'

Then ask for the decision, with the transaction_token from the response.

curl https://acme.authfi.io/apis/regional/v1/agents/authorize \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_7f3a9c21",
    "transaction_token": "'"$TRANSACTION_TOKEN"'",
    "action": "transfer:accounts",
    "resource": "account:4821",
    "context": { "amount": 100, "currency": "USD", "account_type": "business" }
  }'

$ACCESS_TOKEN is the agent's access token. agt_7f3a9c21 is its agent ID, shown as "Client id" on the agent's Connect tab. Both requests are explained in Ask before a sensitive action.

{ "data": { "decision": "allow", "reason": "relationship" } }

Now break a limit. With the limits above, a transfer of 10,000 is over the amount limit. Send the first request again with "amount": 10000. AuthFI does not bind a token to it, and answers 403:

{ "error": "invalid_body", "error_description": "constraint_violated" }

An agent never holds a transaction token for an action outside its limits, so it cannot go on to ask for a decision.

How a limit is evaluated

With the limits and the rule above, the same capability gives different answers for different details.

The agent asks forAnswer
{ "amount": 100, "currency": "USD", "account_type": "business" }allow
{ "amount": 1200, ... }approval_required: the rule sends it to a person
{ "amount": 10000, ... }No transaction token: 403 with constraint_violated
{ "currency": "GBP", ... }No transaction token: 403 with constraint_violated
No amount at allNo transaction token: 403 with constraint_violated

A field named in max, min or in must be sent, and so must a field limited to one value, such as account_type. A request that leaves it out is denied, so an agent cannot pass a limit by omitting the thing it limits.

The limits are checked again when the agent asks for the decision. If a limit was lowered after the token was bound, the answer is deny with a reason such as constraint_violated: amount max.

The decision and its reason

Every decision comes with its reason.

decisionreasonMeaning
allowresource_grant, relationshipSomething granted it
denyno_matchNothing granted it
denypolicy_denyA rule denies it
denyconstraint_violated: …A limit on the capability was exceeded
approval_requiredpolicy_step_upA rule sends it to a person

The same reason is written to the audit record, so you can see afterwards which limit stopped which action.

The order of a decision

AuthFI makes each decision in this order. The first check that fails gives the answer.

  1. Is the agent known and not revoked? If not, the response is 401.
  2. Do the action's details pass the limits on the capability? If not, deny.
  3. Does a rule deny it? If so, deny.
  4. Is it granted? If not, deny.
  5. Does a rule ask for a person? If so, approval_required.
  6. Otherwise, allow.

What is checked for a delegated agent

An agent is delegated or autonomous. See Two types of agent.

A delegated agent that acts for a person through the MCP gateway can do only what both of them may do. The agent's grants and the person's grants are both checked. If either one does not allow the call, it is denied.

Troubleshooting

What you seeCauseFix
deny with no_matchNothing grants the agent this action on this objectGive the agent a role that carries the permission, and name an object of its kind
403 with constraint_violated when you bind a tokenA detail is outside a limit, or a limited field was not sentSend every limited field, within its limit
deny with constraint_violated: …A limit was lowered after the token was boundBind a new token, within the current limits
deny with policy_denyA project rule denies the actionChange the policy. No grant overrides a deny.
401The agent is unknown or revokedCheck the agent ID. A revoked agent stays revoked.

A decision of approval_required is not a failure. The action waits for a person. See Wait for a person.

Next steps