# Access

> Authorization model: action classes (machine-native vs human-governed), capabilities and scopes, role assignments, and propagation.

Source: https://business-api-docs.youhodler.com/docs/concepts/access

Access answers *what an actor is allowed to do, and where*. Who the
actor is — human, machine, federated, on-behalf-of — is the
[Identity](/docs/concepts/identity) concern; this page covers the
authorization layer that sits on top.

The model is the same for every actor: a single capability/scope/role
system applies to humans, service principals, platform-hosted users,
and federated users. Governance never splits into two systems for
different identity sources.

> **Practical rule:** Authorize by capability and scope, not by actor type. The same capability can be granted to a human, a service principal, or both — inside whichever perimeter is appropriate.

## Action Classes

Not every API action needs the same kind of accountability:

- **Machine-native** — repeatable, deterministic work where the human
behind the request does not change its business meaning. Reads,
reconciliation, webhook maintenance, routine provisioning. Service
principal as actor is normal.
- **Human-governed** — actions that require an identifiable actor of
record: governance changes, sensitive lifecycle mutations, payout
destination changes, anything subject to four-eyes or approval. A
real human must be on the request, even when the transport is
machine-driven (see [Acting On Behalf Of A Human](/docs/concepts/identity#acting-on-behalf-of-a-human)).

## Capabilities And Scopes

Authorization is expressed through two independent axes:

- **Capabilities** describe *what* an actor can do — `clients.read`,
`clients.manage`, and so on. They are atomic, named permissions.
- **Scopes** describe *where* the actor can do it. A scope can be a
whole topology perimeter (`enterprise`, `client`) or narrow further
to a specific account (`master-account`, `client-account`).

A caller is allowed an operation only if both axes match: they hold
the required capability, and that capability is granted inside a scope
that covers the target resource.

The benefit is real least-privilege without exploding into bespoke
roles per resource. You can grant the same capability broadly (the
whole enterprise) or narrowly (one client account) by changing only
the scope.

Each grant also declares how far it reaches inside the topology graph:

- **subtree** — the grant covers the named scope and everything
under it; an enterprise-level subtree grant reaches every client
and client account inside.
- **self** — the grant covers only the exact named scope, with no
descendants; useful for narrow exceptions.

Propagation is part of the assignment, not an implicit property of
the topology, so you opt in to coverage rather than getting it by
accident.

## Roles And Role Assignments

Capabilities are bundled into reusable **roles**. A **role assignment**
binds a role to an actor inside a specific scope.

Three layers, three responsibilities:

1. `Capability` — atomic permission name
2. `Role` — named bundle of capabilities
3. `RoleAssignment` — `(actor, role, scope)` triple that grants the
role to the actor inside that scope

Roles are reusable across actors and scopes — the same `Treasury Ops`
role can be assigned to a human user inside one client and to a
service principal inside another, without duplicating the bundle.
Revoking access removes a role assignment; it does not delete the
actor or the role.

## How This Appears In The API

**Request URL — POST**
```http
POST /role-assignments
```
**Request Body — application/json**
```json
{
  "actor_ref": "users/88888888-8888-4888-8888-888888888888",
  "role_ref": "roles/99999999-9999-4999-8999-999999999999",
  "scope_ref": "clients/44444444-4444-4444-8444-444444444444"
}
```
**Response — application/json**
```json
{
  "id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
  "resource": "role-assignments/aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
  "actor_ref": "users/88888888-8888-4888-8888-888888888888",
  "role_ref": "roles/99999999-9999-4999-8999-999999999999",
  "scope_ref": "clients/44444444-4444-4444-8444-444444444444",
  "status": "active"
}
```
