Skip to main content

Policy model

PolicyArc decides each token request with Open Policy Agent (OPA). OPA runs beside the authorization server and evaluates two things the server sends it, Rego rules and data rows. You change a decision by writing a data row or by deploying a rule. You do not change or restart the server.

Rules and data​

Rules are Rego files. The product ships the protocol policies, such as oauth/token.rego, and the shipped controls. You add your own controls as files of your own.

Data rows are JSON. Most shipped controls read their settings from a row named pbac.operator.controls.<control>, such as the denylist row. Controls and segments explains how a control and its row fit together.

The server stores both in its database. It packs them into one bundle, a gzipped tar file of .rego files and a data.json, and serves it at GET /bundles/pbac/bundle.tar.gz. OPA long-polls that endpoint, and the server wakes the poll when a rule or row changes. A change reaches decisions a few seconds after you save it. We saw a data write take effect within about three seconds.

How a token request is decided​

The token policy, oauth.token, works through the request in this order.

  1. It refuses the request outright on a protocol check. These include a client or subject on the denylist, a grant the client is not entitled to, and a public client asking for client credentials.
  2. It resolves what the client is entitled to. A client_id entry in the client entitlements row comes first, then a software_id entry keyed by the software statement's sub claim, then the client's software statement.
  3. It keeps the requested resources the client is entitled to.
  4. It evaluates each kept resource, once for each requested action. An action is refused when a subject restriction or the resource's own scope list rules it out, or when any control adds a reason to deny.
  5. It grants the actions that survived. The request fails when no resource the client named has a surviving action.

Every reason a control added goes into the decision as deny_reasons, whether the request was refused or narrowed. A refused request also gets one reason, such as client_denied or all_resources_denied. The audit log keeps both.

Where your own controls run​

The aggregator package oauth.evaluations_ext collects deny, obligations and token lifetimes from every package under pbac.controls and every connector package under pbac.connectors. You add a control by deploying a file in its own package. Nothing else is edited.

Contributions combine without priority. Denial reasons and obligations are unions, the shortest token lifetime wins, and single use wins when any control asks for it. A control you add cannot remove another control's denial.

The token, introspect and authorize policies run your controls. Registration and the AuthZEN evaluation endpoint use other policies and do not. Rego input and output lists the entry points.

Next steps​