---
title: "§9 Authorization"
description: "Normative authorisation model: Principal, scope, the five capabilities, evaluation order, denial reasons, and audit attribution."
canonical: https://harnesscontextprotocol.io/docs/specification/authorization
---

# §9 Authorization

> Normative authorisation model: Principal, scope, the five capabilities, evaluation order, denial reasons, and audit attribution.

Packs declare effect class (§4). Runtimes decide who may cause that effect.

## 9.1 Principal

1. Every exec, connect, install, and Sense delivery MUST be attributed to exactly
   one Principal.
2. The Principal MUST be established by the runtime from an authenticated
   session or credential. It MUST NOT be taken from the exec envelope.
3. Principal kinds are informative: `human`, `service`, `agent`, `mothership`.

## 9.2 Scope

1. Tenant MUST come from the Principal's session. A runtime MUST NOT select
   the tenant from `args`.
2. Project MUST be resolved when the command's or trigger's land is `brain`.
   Absent project scope, the runtime MUST deny with
   `privacy.land brain requires project_id`.
3. For land `brain`, the runtime MUST verify project membership; tenant
   membership alone is insufficient.
4. Arguments such as `--entity` MAY refine Binding-scoped accounts within the
   resolved scope.

## 9.3 Separation

| Layer | Declares | Owner |
|-------|----------|-------|
| Policy | `operation`, `land`, `confirm` | Pack author |
| Binding | Credential mode and path | Pack declares; runtime mints |
| Principal | Who acts | Runtime |
| Capability grants | Who may cause which effect | Runtime |
| Tenant / Project | Scope | Runtime |

Packs MUST NOT embed user allow-lists, roles, or credentials.

## 9.4 Capabilities

A runtime MUST implement, at minimum, these five axes.

| Capability | Gates |
|------------|-------|
| `pack.install` | Placing a pack in a tenant's catalog or store |
| `pack.connect` | Establishing or refreshing Binding |
| `verb.exec.read` | Executing a command with `operation: read` |
| `verb.exec.write` | Executing a command with `operation: write` |
| `sense.enable` | Delivering declared triggers to a sink |

1. A runtime MAY scope a grant to a `pack_id` and further to specific
   `verb_keys`.
2. A multi-tenant runtime MUST NOT collapse `verb.exec.read`,
   `verb.exec.write`, and `pack.connect` into a single boolean.
3. `pack.connect` MUST be evaluated for connect commands regardless of any
   `verb.exec.write` grant.
4. A runtime MUST fail closed: absence of a matching grant is a denial.

## 9.5 Evaluation order

Authorization runs inside the exec pipeline, in the order of §6.3:

```text
1. Resolve pack, activation, and Policy entry                       (§6.3 steps 1 to 3)
2. Authenticate Principal; resolve Tenant (+ Project if land = brain) (step 4)
3. Assert capability for pack_id (+ verb_key)                        (step 5)
4. Enforce confirm                                                   (step 6)
5. Mint Binding, fail closed                                         (step 7)
6. Execute Adapter                                                   (step 8)
7. Audit                                                             (step 9)
```

A runtime MUST NOT reorder these steps such that an Adapter could run before a
denial would have been produced. Every Invoker (an agent, an API, a UI, a
person at a terminal) reaches a command through this order, and a runtime MUST
NOT give an Invoker a path to a `verb_key` that skips a step.

*Informative.* RFC 0006 (draft) adds access modes, allow, ask and deny rules,
and approvals at step 4.

## 9.6 Audit

The reference runtime writes one line per decision to `audit.jsonl`; see
[Access](/docs/concepts/access#audit).


1. Every `write` MUST be recorded with:
   `Principal + Tenant (+ Project) + Binding identity + pack_id + verb_key + operation`.
2. Every `read` SHOULD be recorded with the same tuple.
3. Every denial SHOULD be recorded with its reason.
4. Binding identity and Principal MUST be distinct fields.

## 9.7 Denial reasons

Denials MUST be returned as `ok: false` result envelopes. The `error` string
SHOULD begin with `denied:` for grant and scope denials and SHOULD name the
missing capability.

| Reason | Condition |
|--------|-----------|
| `denied: missing verb.exec.read for <pack>.<verb>` | No read grant |
| `denied: missing verb.exec.write for <pack>.<verb>` | No write grant |
| `denied: missing pack.connect` | Connect without grant |
| `denied: missing pack.install` | Install without grant |
| `denied: missing sense.enable` | Sense delivery without grant |
| `denied: privacy.land brain requires project_id` | No project scope |
| `confirm required` | Gate not satisfied |

## 9.8 Cross-mode execution

A runtime MUST refuse a command whose Binding mode is `mothership` when the
Principal is not an operator, unless an explicit elevation grant is present. This
applies regardless of how the operator binary became reachable.

## 9.9 Out of scope

*Informative.* Role table schemas, row-level security, IdP integration, session
formats, and host paths are adopter profiles. The protocol fixes only the axes,
the order, and the tuple.

## Sitemap

- [Documentation](https://harnesscontextprotocol.io/docs)
- [Packs](https://harnesscontextprotocol.io/packs)
- [Glossary](https://harnesscontextprotocol.io/docs/reference/glossary)
- [llms.txt](https://harnesscontextprotocol.io/llms.txt)
- [llms-full.txt](https://harnesscontextprotocol.io/llms-full.txt)
- [OpenAPI](https://harnesscontextprotocol.io/openapi.json)
- [MCP](https://harnesscontextprotocol.io/mcp)
