# Authorization

Cocoon replaces traditional role-based access control (RBAC) with **UCAN** (User Controlled Authorization Networks), a capability-based delegation system where permissions are cryptographically chained rather than assigned by a central authority.

{% hint style="info" %}
UCAN inverts the access control model. Instead of asking "does this user have the admin role?", the system asks "does this token prove the holder can perform this specific action?" Permissions travel with the token, not the identity.
{% endhint %}

## Why UCAN Instead of RBAC

In a role-based system, a central authority decides what each role can do, and users are assigned roles. This requires a trusted registry and creates a single point of control — and failure.

UCAN works differently. Every capability is a statement: "I can do X." Delegation is: "I grant you the ability to do X, subject to restrictions Y." The chain of grants from the original resource owner to the final invoker is verifiable without contacting any central authority.

| Concept              | RBAC              | UCAN                            |
| -------------------- | ----------------- | ------------------------------- |
| Permission storage   | Central database  | Token payload                   |
| Trust anchor         | Identity provider | Cryptographic signature         |
| Delegation           | Role assignment   | Token issuance with attenuation |
| Revocation           | Delete from DB    | On-chain revocation registry    |
| Offline verification | Not possible      | Yes, via signature chain        |

## Delegation Model

A UCAN token is a signed JWT-style structure containing: the issuer DID, the audience DID, an expiry timestamp, and a set of capabilities the audience may exercise. Attenuation means a delegatee can never grant more than the delegator holds.

```mermaid
flowchart TD
    A["Fund Manager\n(Root Authority)"] -->|"issues UCAN\n/token/owner/*"| B["Portfolio Manager\n(DID: did:pkh:eip155:1:0xABC)"]
    B -->|"delegates\n/token/investor/* only\n(attenuated)"| C["Investor Relations\n(DID: did:key:z6Mk...)"]
    C -->|"further delegates\n/token/investor/view\n(further attenuated)"| D["External Auditor\n(DID: did:pkh:eip155:1:0xDEF)"]
    D -->|"invokes RPC\nwith UCAN proof chain"| E["UCAN Verifier Contract\n(on-chain)"]
    E -->|"walks chain:\ncheck signatures,\ncapabilities, expiry,\nrevocation"| F{Valid?}
    F -->|Yes| G["Action Permitted"]
    F -->|No| H["Action Denied"]
```

Each hop in the chain must be verifiable independently. The external auditor's token embeds references (CIDs) to all parent tokens in the chain, so the verifier can reconstruct the full proof without any external calls to a directory service.

## EIP-8141 Integration

EIP-8141 defines native account abstraction for Cocoon's execution layer. UCAN tokens are embedded directly in frame transactions — the Cocoon equivalent of EIP-4337 UserOperations.

When a frame transaction arrives at the node, the UCAN verifier contract is called before execution proceeds:

1. The frame payload includes a `ucanProof` field containing the full delegation chain (or CIDs pointing to tokens stored via torrent-ccip).
2. The node's RPC middleware extracts and validates: signature validity, capability match, expiry, and revocation status.
3. On-chain, the UCAN verifier contract performs final verification for any action that mutates state.
4. The revocation registry is checked — a token CID appearing in the registry is immediately rejected regardless of signature validity.

{% hint style="warning" %}
UCAN tokens have expiry timestamps. Tokens issued with very short expiry windows improve security but require more frequent re-delegation. Tokens issued without expiry rely entirely on the revocation registry for invalidation — ensure your revocation registry is up to date.
{% endhint %}

## DID Bridging

Cocoon supports multiple DID methods to accommodate different key types and contexts:

| DID Method | Key Material                 | Use Case                       |
| ---------- | ---------------------------- | ------------------------------ |
| `did:pkh`  | Ethereum address (secp256k1) | Standard EOA accounts          |
| `did:key`  | ML-KEM-768 post-quantum key  | Post-quantum secure delegation |
| `did:key`  | Ed25519                      | Lightweight service identities |

The DID bridge resolves between these namespaces, allowing a single UCAN chain to span an Ethereum address (fund manager), a contract wallet (portfolio manager), and a post-quantum key (automated agent).

## Signing Backends

UCAN tokens must be signed. Cocoon supports the full spectrum of Ethereum signing mechanisms:

| Backend             | Standard          | Description                      |
| ------------------- | ----------------- | -------------------------------- |
| EOA                 | ERC-191 / ERC-712 | Standard private key signing     |
| Contract wallet     | ERC-1271          | `isValidSignature` on-chain      |
| Account abstraction | ERC-4337          | Bundled UserOperation signing    |
| Delegated signing   | EIP-7702          | EOA delegates to contract logic  |
| Native AA           | EIP-8141          | Frame-native account abstraction |

This means any Ethereum account — hardware wallet, multisig, smart contract wallet, or AA account — can be the root authority or a delegate in a UCAN chain.

## Capability Namespaces

Capabilities are structured as hierarchical namespaces. A capability at `/token/owner/*` implies all capabilities nested beneath it. Attenuation means a delegatee can hold `/token/investor/view` but never escalate to `/token/owner/*` even if they issue tokens to themselves.

| Namespace           | Scope                                                        |
| ------------------- | ------------------------------------------------------------ |
| `/token/owner/*`    | Full token ownership actions (transfer, burn, configure)     |
| `/token/agent/*`    | Automated agent actions on behalf of token holder            |
| `/token/investor/*` | Investor-facing actions (subscribe, redeem, view holdings)   |
| `/storage/*`        | Read/write access to torrent-ccip stored data                |
| `/id/*`             | Identity management (issue credentials, update DID document) |
| `/webf/*`           | Web hosting management (publish, update, delete sites)       |
| `/auth/*`           | Authorization management (delegate, revoke, inspect)         |

Example delegation: a fund manager holds `/token/owner/*` and delegates `/token/investor/subscribe` to an investor relations system, which further delegates `/token/investor/subscribe` (no further attenuation possible — the leaf capability) to a specific investor's DID.

## On-Chain Verification

Two contracts handle UCAN lifecycle on-chain:

**UCAN Verifier** — stateless contract that validates a proof chain. Given a UCAN token and its parent chain, it: verifies each signature using the appropriate backend (EOA, ERC-1271, etc.), checks capability containment at each delegation step, and confirms no token has expired.

**Revocation Registry** — stores CIDs of revoked tokens. Any party in the delegation chain can revoke a token they issued. Checking revocation requires a single `mapping(bytes32 => bool)` lookup per token in the chain.

```mermaid
sequenceDiagram
    participant C as Client
    participant N as Node RPC Middleware
    participant V as UCAN Verifier Contract
    participant R as Revocation Registry

    C->>N: RPC call + UCAN proof chain
    N->>N: Extract and parse proof chain
    N->>R: Check each token CID against registry
    R-->>N: None revoked
    N->>V: Verify full chain on-chain
    V->>V: Check signatures, capabilities, expiry
    V-->>N: Valid
    N->>N: Execute RPC method
    N-->>C: Result
```

## Token Distribution

UCAN tokens can be large (a deep delegation chain may contain several parent tokens). Rather than embedding full token payloads in every transaction, Cocoon stores tokens via torrent-ccip and references them by CID. The verifier resolves CIDs to content via the BitTorrent layer at verification time.

This means delegation chains are:

* Content-addressed (CID is a cryptographic commitment to the token content)
* Decentrally distributed (no single token registry)
* Accessible offline if the node has cached the torrent segments

## Argument-Level Permissions

Standard RBAC and even capability-based systems like UCAN typically enforce permissions at the function level: "this role can call `transfer`." Cocoon's `PermissionRegistry` contract takes this one step further — it enforces constraints on the **arguments** of each call.

{% hint style="info" %}
Argument-level permissions are a key Cocoon differentiator. Most institutional permissioning systems (including Prividium) only enforce function-level access. Cocoon can encode rules like "Traders may transfer, but only amounts below $1,000,000" directly in the on-chain registry.
{% endhint %}

### How It Works

The `PermissionRegistry` contract maps (role, method, argument) tuples to allowed ranges or values. When the backend proxy receives an RPC call, it reads the caller's role from their session, checks the registry for the relevant constraints, and enforces them before forwarding the call to the chain.

```mermaid
flowchart TD
    A["Client sends RPC call\ne.g. token_transfer(amount=2M)"] --> B["Backend proxy"]
    B --> C["Lookup caller role\nfrom session cache"]
    C --> D["Query PermissionRegistry\nfor (role, method, arg) constraints"]
    D --> E{Constraint satisfied?}
    E -->|Yes| F["Forward to Erigon node"]
    E -->|No| G["Return 403 with\npermission rule details"]
```

### Default Permission Rules

The MVP ships with the following pre-configured argument-level limits:

| Role         | Method            | Argument | Constraint   |
| ------------ | ----------------- | -------- | ------------ |
| Trader       | `token_transfer`  | `amount` | ≤ $1,000,000 |
| SeniorTrader | `token_transfer`  | `amount` | ≤ $5,000,000 |
| Compliance   | `token_freeze`    | *(any)*  | Unrestricted |
| Auditor      | All write methods | *(any)*  | Blocked      |
| Regulator    | All write methods | *(any)*  | Blocked      |
| Admin        | All methods       | *(any)*  | Unrestricted |

### Managing Permission Rules

Rules are managed via the admin dashboard under **Permissions**, or directly via the `PermissionRegistry` contract. Adding a rule:

```json
// Grant SeniorTrader transfer up to $5M
{
  "role": "SeniorTrader",
  "method": "token_transfer",
  "argument": "amount",
  "maxValue": "5000000000000000000000000"
}
```

The dashboard provides a visual rule editor that translates human-readable limits (e.g. "$5M") into the appropriate on-chain encoding.

### Permission Acknowledgment

When a user attempts an action blocked by an argument-level rule (e.g. a Trader tries to transfer $2M), the frontend displays the blocked request with the specific rule that was violated — for example: "Your Trader role allows transfers up to $1,000,000. This request requires SeniorTrader authorization." This creates an auditable permission acknowledgment workflow.

## User Roles and Session Management

### Role Definitions

Cocoon's backend assigns one of six roles to each authenticated user. Roles are stored in the user database and checked on every authenticated RPC call.

| Role             | Capabilities                                                                               |
| ---------------- | ------------------------------------------------------------------------------------------ |
| **Admin**        | Full access: user management, KYC approval, permission configuration, all chain operations |
| **Trader**       | Transfer tokens (≤ $1M), subscribe/redeem MMF shares, send IBAN payments, swap assets      |
| **SeniorTrader** | Transfer tokens (≤ $5M), all Trader actions                                                |
| **Compliance**   | Read all transactions and positions; configure compliance rules; freeze/unfreeze wallets   |
| **Auditor**      | Read-only access to transactions and audit logs                                            |
| **Regulator**    | Read-only access to selective disclosure endpoints and regulatory reports                  |

### Session Lifecycle

Authentication is managed by the user database service (port 8548). Sessions use a **sliding window** model: every authenticated API call extends the session TTL.

```mermaid
sequenceDiagram
    participant User
    participant Frontend
    participant UserDB as User DB (8548)
    participant Backend as Backend Proxy (8546)

    User->>Frontend: Login (email + password)
    Frontend->>UserDB: POST /auth/login
    UserDB-->>Frontend: { token, expires_at } (30 min from now)
    Frontend->>Frontend: Store token + expires_at in localStorage

    Note over Frontend,Backend: Every page load / API call
    Frontend->>UserDB: GET /auth/me (with token)
    UserDB-->>Frontend: { user profile, new expires_at } ← window slides
    Frontend->>Backend: RPC call (with token in Authorization header)
    Backend->>Backend: Check session cache (5s TTL)
    Backend-->>Frontend: Result
```

The 5-second session cache in the backend proxy means at most one user DB round-trip per 5 seconds per user — the proxy never hammers the user DB on every call.

**Session TTL** defaults to 30 minutes and is configurable via `PATCH /admin/settings` on the user DB service.

### KYC Gate

All new user accounts start with `kyc_status: pending`. The portfolio, payment, and swap flows are blocked until `kyc_status` reaches `verified`. See [KYC & User Management](/operators/kyc-and-user-management.md) for the full lifecycle.

## Login Flow (SIWE)

For production deployments using the full UCAN auth stack, login proceeds via Sign-In with Ethereum (ERC-4361):

1. User connects wallet and signs a SIWE message.
2. Server verifies the signature and recovers the Ethereum address.
3. Server discovers on-chain roles (token owner, agent, investor, KYC issuer) via contract queries.
4. Server issues a UCAN session token with capabilities matching the discovered roles.
5. App adapts navigation and available actions to the user's role set.

The `auth_login` RPC method encapsulates steps 2–4. See the [RPC Reference](/reference/rpc-reference.md#auth_login) for the full method signature.

## Key APIs

| Method                  | Description                                                                             |
| ----------------------- | --------------------------------------------------------------------------------------- |
| `auth_login`            | Verify a SIWE signature, discover on-chain roles, and return a UCAN session token       |
| `auth_createDelegation` | Issue a new UCAN token delegating a subset of the caller's capabilities to a target DID |
| `auth_verify`           | Verify a UCAN proof chain for a given capability without executing any action           |
| `auth_inspect`          | Decode and display the full delegation chain for a given UCAN token CID                 |
| `auth_revoke`           | Add a token CID to the on-chain revocation registry                                     |
| `auth_getSession`       | Check validity and remaining lifetime of a session token                                |
| `auth_refreshRoles`     | Re-discover on-chain roles without re-logging in                                        |

```json
// auth_createDelegation example
{
  "method": "auth_createDelegation",
  "params": {
    "audience": "did:pkh:eip155:1:0xAbC123...",
    "capabilities": ["/token/investor/subscribe", "/token/investor/view"],
    "expiry": 1780000000,
    "restrictions": {
      "maxAmount": "100000000000000000000"
    }
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cocoon.erigon.tech/components/authorization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
