Permissions & Policies
How each agent action gets its own scoped, constrained permission
Hawcx replaces broad session-level permissions with Task-Based Access Control (TBAC): every single tool invocation gets its own scoped, constrained authorization token.
Why Not OAuth Scopes?
OAuth scopes like orders:read grant broad session-level permissions. Once an agent has an OAuth token with orders:read, it can read every order, every time, until the token expires.
TBAC is different:
| OAuth Scopes | Hawcx TBAC | |
|---|---|---|
| Granularity | Per-session | Per-request |
| Who sets permissions | Agent declares at registration | Your access policy engine (not the agent) |
| Constraints | None natively | Max calls, time limits, record limits, encryption requirements |
| Tool binding | Generic resource:action | Specific tool: mcp:git_push, a2a:invoice_lookup |
| Replay protection | Bearer token (replayable) | Single-use, cryptographically bound to session |
| Delegation | Implicit or absent | Explicit depth limit (decreases by 1 at each hop) |
What's in a Permission Token
Every token contains a structured permission object with these fields:
| Field | Type | What it controls |
|---|---|---|
tool | string | Which tool/operation is authorized (e.g., mcp:git_push) |
constraints | object | Limits like max_calls, time_bound, max_records, require_encryption |
agent_instance_id | string | Which agent this token is for |
aud | string | Which service can accept this token (prevents cross-service misuse) |
delegation_depth | integer | How many times this permission can be re-delegated (decreases by 1 at each hop) |
policy_epoch | integer | Ensures the token uses the current policy version |
How Permissions Are Set
The agent does not set its own permissions
This is a deliberate security property. The agent's LLM runtime does not construct permissions from natural language. Permissions are determined by policy engines running outside the agent's process.
Your access policy engine evaluates:
- Which agent is this? Its agent ID
- Which human registered it? The human's organizational identity
- What role does that human hold? Their IAM role
- Does policy permit this tool/resource/action? Policy evaluation result
The result is a constrained permission token, or DENY.
// Example policy (Cedar syntax)
permit(
principal == Agent::"code-deploy-agent",
action == Action::"mcp:git_push",
resource == Repo::"main-app"
) when {
context.time.hour >= 9 && context.time.hour <= 17 &&
context.deployment_env == "staging"
};This policy says: the code-deploy-agent can push to the main-app repo, but only during business hours, and only to staging.
Constraint Enforcement
Constraints are embedded in each token and enforced server-side:
| Constraint | What It Enforces |
|---|---|
max_calls: 1 | Single invocation only (default for most tools) |
time_bound: 60 | Token must be used within 60 seconds of minting |
max_records: 100 | Limits the number of records returned |
require_encryption: true | Response must be encrypted end-to-end |
delegation_depth: 0 | Cannot delegate this authorization to another agent |
These constraints are cryptographically bound to the token. Modifying them invalidates the token entirely.