Programming · free software · the open webSubscribe via RSS

Pass a capability instead of looking up ambient authority

A capability combines an object reference with permission to use it. Passing a narrow read-only handle can make authority explicit and limited to the resource and operations the recipient needs.

Make authority visible in the interface

Consider a reporting task that needs to read one document. A global service might expose account.getDocument(documentId), then check the caller’s account and permissions on each request. The account object and its lookup rules are ambient authority: code can reach the broad service and ask it to find resources by name. The interface must defend every lookup against confused assumptions about which account or document the caller intended.

A capability-oriented design can instead pass the task a handle for that document with only read operations. The reference designates the particular object, and possession of the reference confers the authority to invoke its exposed methods. Cap’n Proto RPC describes interface references this way: they identify an object and grant permission to call it; references can be passed as parameters or included in messages. [2]

Narrow handles constrain the reachable actions

The difference is concrete in the API surface. A handle with read(offset, length) offers no delete, rename, or account-wide search operation. The caller does not need to supply a document identifier on every call, so it cannot accidentally substitute another identifier in a later request. This is a form of attenuation: code that receives a read-only view has less authority than code holding the owner’s full document interface. The service can implement separate interfaces or wrapper objects to expose only the permitted methods.

Object identity also changes the question the server answers. A global lookup asks, “Which document does this name refer to for this caller right now?” A passed reference asks, “May this holder invoke this particular object?” The latter does not eliminate policy; the code that creates or shares the reference decides whether delegation is appropriate, and the object can still apply additional rules. It makes the grant explicit at the point where authority crosses a boundary. [2]

Delegation is a design operation

Suppose a user shares one report with a job runner. The user can give the runner a read-only handle to that report rather than credentials that let it query the entire account. The runner may pass the handle to a helper if delegation is allowed by the surrounding system, but each recipient gains only the authority represented by the reference it receives. In Cap’n Proto RPC, capabilities are connection-scoped references; the host assigns identifiers specific to the connection, and the receiver’s possession is what permits calls through that reference. [2]

This model can reduce the reach of a bug. If the runner is compromised, a narrow handle limits which methods and objects it can directly reach. It does not protect data the runner has already read, nor does it automatically secure the channel that carries the reference. The RPC documentation explicitly treats encryption separately, noting that encryption can be layered over TLS. A capability controls authority to an object; transport security protects communication; application policy governs how the object behaves. [2]

Use analogies carefully

A bearer URL is a useful analogy in one respect: someone who possesses the token may gain access, so the token must be shared deliberately and can be scoped to a resource. But a URL is not identical to every object capability. A URL may be a name resolved by a global HTTP service, while an object capability is a reference to an object that also carries permission to invoke its interface. Systems differ in how references are transported, revoked, persisted, and delegated, so the analogy should clarify possession rather than collapse the designs into one.

Sandstorm’s security documentation makes the boundary concrete. The platform isolates individual resources and decides whether a user can reach a grain, while the app must enforce finer permission levels such as read versus write. A narrow interface is useful only when its implementation respects that distinction. [1] Instead of giving a component broad credentials, pass the object and operations it needs; then review where that authority can flow.

References

  1. Sandstorm security practices
  2. Cap’n Proto RPC protocol

Suggest a correction · All posts