Skip to main content

Delegation and approval

An agent rarely works alone. It hands a task to another agent, or it reaches a step that a person should approve first. PolicyArc handles the first with token exchange and the second with Client Initiated Backchannel Authentication (CIBA). Both leave the decision with policy, not with the agent.

Hand work to another agent​

The agent that holds a token asks /token to exchange it for a new one, under the token exchange grant of RFC 8693. The new token can ask for fewer scopes. When the exchange names an actor, the new token records it in an act claim. When the token being exchanged already had an actor, the new act nests the earlier one, so the chain of agents stays on the token. That happens only when the new exchange names an actor too. An exchange without an actor_token issues a token with no act claim, and the earlier chain is dropped. A token issued for a user keeps that user as its subject through the exchange.

Policy runs on the exchange like any token request. It sees the exchanging client in input.context.client and the actor in input.context.actor, so a control can limit which agents may delegate and to whom. Delegation chains is one such control.

Exchange a token has the requests and the answers we saw, including a known issue with the scope check on 0.65.0.

Make an agent wait for a person​

The human approval control holds a request until a person approves it. Its rules live in the row pbac.operator.controls.ciba_approval. Each rule matches a requested resource by its type, usually the type of a rich authorization request, and one condition on its fields. It names the approver.

When a rule matches, the agent's token request is not refused. It gets HTTP 400 approval_required, with the approver and the message that person will see. Then the agent does three things.

  1. It sends the same request to /bc-authorize, with the approver and the message. PolicyArc notifies your approval service and answers with an auth_req_id.
  2. It polls /token with the CIBA grant and the auth_req_id. Until someone decides, the answer is authorization_pending.
  3. If the person approves, the next poll returns the token. If they refuse, it returns access_denied with Authorization was denied.

The agent cannot pick the approver or skip the wait. The approver comes from the rule, and /bc-authorize refuses a request that policy would grant without approval.

What the approver sees​

PolicyArc sends the approval service a signed request with the message, the client's name and what it asks for. The approval service decides how to reach the person, such as a push notification or a page, and what they see. The message comes from the rule's binding_message_template, filled in from the request, such as Allow the agent to write /reports/q3.txt. Write it so the person knows what they are agreeing to without opening anything else.

What the agent sees​

MomentWhat the agent gets
It asks for something a rule holdsHTTP 400 approval_required, with login_hint naming the approver and error_description holding the message
It polls before a decisionHTTP 400 authorization_pending
The person approvesA token. A rich authorization request comes back in authorization_details.
The person refusesHTTP 400 access_denied, Authorization was denied
No one decides in timeHTTP 400 expired_token

The approved token's audit row names the approver as its subject.

Hold an agent's write for a person's approval runs all of this on your environment. Get a person's approval with CIBA is the reference for /bc-authorize, the poll and the approval service's contract.