|
| 1 | +# Broker Setup Guide |
| 2 | + |
| 3 | +> **Purpose:** Set up the broker so the [sample apps](sample-app-mini-max.md) can run. |
| 4 | +> The apps need specific scope ceilings configured per app. |
| 5 | +> **Audience:** Operators registering apps, or developers verifying their app's ceiling. |
| 6 | +> **Prerequisites:** Broker running. See [Getting Started: Operator](../broker/docs/getting-started-operator.md) for broker deployment. |
| 7 | +
|
| 8 | +--- |
| 9 | + |
| 10 | +## Overview |
| 11 | + |
| 12 | +Every app needs a registered scope ceiling. The ceiling is the **maximum** scope any agent created by that app can request. If an app requests a scope outside its ceiling, the broker returns `403` and no token is issued. |
| 13 | + |
| 14 | +The app **cannot** discover its own ceiling — the operator sets it when registering the app, and the broker enforces it silently at agent creation time. You must track ceilings outside the broker. |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## Step 1: Register the App |
| 19 | + |
| 20 | +Register the app once. Replace the scopes with what your operator approved. |
| 21 | + |
| 22 | +### Option A: Using aactl (recommended) |
| 23 | + |
| 24 | +```bash |
| 25 | +export AACTL_BROKER_URL="http://localhost:8080" |
| 26 | +export AACTL_ADMIN_SECRET="your-admin-secret" |
| 27 | + |
| 28 | +aactl app register \ |
| 29 | + --name sample-apps \ |
| 30 | + --scopes "read:data:*,write:data:*,read:customers:*,write:orders:*,read:files:*,write:files:*,read:monitoring:*,send:webhooks:*,read:billing:*,write:notes:*,read:audit:all,delete:customers:*,read:logs:*" |
| 31 | +``` |
| 32 | + |
| 33 | +### Option B: Using raw HTTP (admin API) |
| 34 | + |
| 35 | +Admin auth is not part of the SDK. Use `aactl` or raw HTTP: |
| 36 | + |
| 37 | +```bash |
| 38 | +# 1. Get admin token |
| 39 | +ADMIN_TOKEN=$(curl -s -X POST "http://localhost:8080/v1/admin/auth" \ |
| 40 | + -H "Content-Type: application/json" \ |
| 41 | + -d '{"secret": "your-admin-secret"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") |
| 42 | + |
| 43 | +# 2. Register app with the full ceiling |
| 44 | +curl -X POST "http://localhost:8080/v1/admin/apps" \ |
| 45 | + -H "Content-Type: application/json" \ |
| 46 | + -H "Authorization: Bearer $ADMIN_TOKEN" \ |
| 47 | + -d '{ |
| 48 | + "name": "sample-apps", |
| 49 | + "scopes": ["read:data:*","write:data:*","read:customers:*","write:orders:*","read:files:*","write:files:*","read:monitoring:*","send:webhooks:*","read:billing:*","write:notes:*","read:audit:all","delete:customers:*","read:logs:*"] |
| 50 | + }' |
| 51 | +``` |
| 52 | + |
| 53 | +Save the `client_id` and `client_secret` from the response. The `client_secret` is shown only once. |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +## Step 2: Set Environment Variables |
| 58 | + |
| 59 | +```bash |
| 60 | +export AGENTAUTH_BROKER_URL="http://localhost:8080" |
| 61 | +export AGENTAUTH_CLIENT_ID="sample-apps" |
| 62 | +export AGENTAUTH_CLIENT_SECRET="your-client-secret" |
| 63 | +``` |
| 64 | + |
| 65 | +--- |
| 66 | + |
| 67 | +## Scope Ceiling Reference Per App |
| 68 | + |
| 69 | +Each app requests specific scopes. The **app's ceiling** must cover them, or the broker rejects the agent creation. |
| 70 | + |
| 71 | +### App 1: File Access Gate |
| 72 | + |
| 73 | +``` |
| 74 | +Ceiling needed: read:files:*, write:files:* |
| 75 | +Scopes requested by app: read:files:report-q3 |
| 76 | +``` |
| 77 | + |
| 78 | +The app reads files `report-q3` and `audit-log`. The ceiling must include `read:files:*`. |
| 79 | + |
| 80 | +### App 2: Customer API Gateway |
| 81 | + |
| 82 | +``` |
| 83 | +Ceiling needed: read:customers:* |
| 84 | +Scopes requested by app: read:customers:customer-42, read:customers:customer-99 |
| 85 | +``` |
| 86 | + |
| 87 | +The app fetches customer records by ID. The ceiling must include `read:customers:*`. |
| 88 | + |
| 89 | +### App 3: LLM Tool Executor |
| 90 | + |
| 91 | +``` |
| 92 | +Ceiling needed: read:customers:*, write:orders:*, delete:customers:*, read:audit:all |
| 93 | +Scopes requested by app: read:customers:customer-42, write:orders:customer-42 |
| 94 | + (delete:customers:* and read:audit:all are intentionally not requested — |
| 95 | + this is what the app tests as denied) |
| 96 | +``` |
| 97 | + |
| 98 | +The app exercises scope enforcement. It needs `delete:customers:*` and `read:audit:all` in the ceiling **only to demonstrate denials** — the app intentionally does not request them, so the broker blocks them. |
| 99 | + |
| 100 | +### App 4: Data Pipeline Runner |
| 101 | + |
| 102 | +``` |
| 103 | +Ceiling needed: read:data:*, write:data:* |
| 104 | +Scopes requested by app: read:data:source-batch-101, read:data:source-batch-102, |
| 105 | + write:data:dest-batch-101, write:data:dest-batch-102 |
| 106 | +``` |
| 107 | + |
| 108 | +The pipeline reads from source partitions and writes to destination partitions. The ceiling must include `read:data:*` and `write:data:*`. |
| 109 | + |
| 110 | +### App 5: Audit Log Reader |
| 111 | + |
| 112 | +``` |
| 113 | +Scope ceiling: N/A — no agent scopes needed |
| 114 | +What it uses: Admin auth only (aactl or raw HTTP admin API) |
| 115 | + POST /v1/admin/auth with AACTL_ADMIN_SECRET |
| 116 | + GET /v1/audit/events with admin Bearer token |
| 117 | +``` |
| 118 | + |
| 119 | +The SDK is not used. The app uses raw HTTP to authenticate as admin and read events. The SDK (`AgentAuthApp`) only handles app-level operations — it has no admin auth path. |
| 120 | + |
| 121 | +### App 6: Token Lifecycle Manager |
| 122 | + |
| 123 | +``` |
| 124 | +Ceiling needed: read:data:* |
| 125 | +Scopes requested by app: read:data:sync-source |
| 126 | +``` |
| 127 | + |
| 128 | +The worker reads from a sync source. The ceiling must include `read:data:*`. |
| 129 | + |
| 130 | +### App 7: Multi-Tenant Agent Factory |
| 131 | + |
| 132 | +``` |
| 133 | +Ceiling needed: read:data:* |
| 134 | +Scopes requested by app: read:data:invoices:{tenant_id}, read:data:reports:{tenant_id} |
| 135 | + (tenant IDs are substituted at runtime: acme-corp, globex) |
| 136 | +``` |
| 137 | + |
| 138 | +The factory substitutes tenant IDs at runtime. The ceiling must include `read:data:*` — the specific `{tenant_id}` identifiers are not in the ceiling. |
| 139 | + |
| 140 | +### App 8: Webhook Dispatcher |
| 141 | + |
| 142 | +``` |
| 143 | +Ceiling needed: send:webhooks:* |
| 144 | +Scopes requested by app: send:webhooks:order-confirmation |
| 145 | +``` |
| 146 | + |
| 147 | +The app sends outbound webhooks. The ceiling must include `send:webhooks:*`. |
| 148 | + |
| 149 | +### App 9: Scope Ceiling Guard |
| 150 | + |
| 151 | +``` |
| 152 | +Ceiling needed: read:data:test, read:data:*, write:data:*, admin:revoke:*, read:logs:* |
| 153 | + (intentionally includes out-of-bounds scopes for testing) |
| 154 | +Scopes requested by app: read:data:test — inside ceiling → should succeed |
| 155 | + admin:revoke:asterisk — outside ceiling → BLOCKED (403) |
| 156 | + read:logs:system — outside ceiling → BLOCKED (403) |
| 157 | +``` |
| 158 | + |
| 159 | +The purpose of this app is to demonstrate the broker blocking requests that exceed the ceiling. Without `admin:revoke:*` and `read:logs:*` in the ceiling, the app cannot show the blocking behavior. |
| 160 | + |
| 161 | +### App 10: Renewal with Revocation Detection |
| 162 | + |
| 163 | +``` |
| 164 | +Ceiling needed: read:monitoring:* |
| 165 | +Scopes requested by app: read:monitoring:alerts |
| 166 | +``` |
| 167 | + |
| 168 | +The continuous agent reads monitoring alerts. The ceiling must include `read:monitoring:*`. |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +## Complete Ceiling for All Apps |
| 173 | + |
| 174 | +To run every app without modification, register the app with this ceiling: |
| 175 | + |
| 176 | +### aactl |
| 177 | + |
| 178 | +```bash |
| 179 | +aactl app update sample-apps \ |
| 180 | + --scopes "read:data:*,write:data:*,read:customers:*,write:orders:*,read:files:*,write:files:*,read:monitoring:*,send:webhooks:*,read:billing:*,write:notes:*,read:audit:all,delete:customers:*,read:logs:*" |
| 181 | +``` |
| 182 | + |
| 183 | +### HTTP |
| 184 | + |
| 185 | +```bash |
| 186 | +curl -X POST "http://localhost:8080/v1/admin/apps/sample-apps" \ |
| 187 | + -H "Authorization: Bearer $ADMIN_TOKEN" \ |
| 188 | + -H "Content-Type: application/json" \ |
| 189 | + -d '{ |
| 190 | + "name": "sample-apps", |
| 191 | + "scopes": ["read:data:*","write:data:*","read:customers:*","write:orders:*","read:files:*","write:files:*","read:monitoring:*","send:webhooks:*","read:billing:*","write:notes:*","read:audit:all","delete:customers:*","read:logs:*"] |
| 192 | + }' |
| 193 | +``` |
| 194 | + |
| 195 | +--- |
| 196 | + |
| 197 | +## Broker Start Command |
| 198 | + |
| 199 | +```bash |
| 200 | +AA_ADMIN_SECRET="your-admin-secret" \ |
| 201 | +AA_DB_PATH="/tmp/agentauth.db" \ |
| 202 | +AA_DEFAULT_TTL="300" \ |
| 203 | +AA_MAX_TTL="600" \ |
| 204 | +./broker |
| 205 | +``` |
| 206 | + |
| 207 | +| Flag | Purpose | |
| 208 | +|------|---------| |
| 209 | +| `AA_ADMIN_SECRET` | Admin password for operator tasks (app registration, revocation, audit) | |
| 210 | +| `AA_DB_PATH` | SQLite database path — audit log and revocation data | |
| 211 | +| `AA_DEFAULT_TTL` | Default agent token TTL in seconds (300 = 5 minutes) | |
| 212 | +| `AA_MAX_TTL` | Maximum TTL any token can be issued with (clamping ceiling) | |
| 213 | + |
| 214 | +--- |
| 215 | + |
| 216 | +## Quick Verification |
| 217 | + |
| 218 | +```bash |
| 219 | +# Broker is up |
| 220 | +curl http://localhost:8080/v1/health |
| 221 | + |
| 222 | +# App auth works |
| 223 | +curl -X POST "http://localhost:8080/v1/app/auth" \ |
| 224 | + -H "Content-Type: application/json" \ |
| 225 | + -d '{"client_id": "sample-apps", "client_secret": "your-client-secret"}' |
| 226 | +# Returns: {"access_token": "...", "expires_in": 1800} |
| 227 | + |
| 228 | +# List apps (admin) |
| 229 | +aactl app list |
| 230 | +``` |
| 231 | + |
| 232 | +--- |
| 233 | + |
| 234 | +## Troubleshooting |
| 235 | + |
| 236 | +| Symptom | Cause | Fix | |
| 237 | +|--------|-------|-----| |
| 238 | +| `401` on app auth | Wrong `client_id` or `client_secret` | Re-register the app and save the credentials | |
| 239 | +| `403` on agent creation | Requested scope outside app ceiling | Extend the app ceiling with `aactl app update`, or narrow the requested scope | |
| 240 | +| `403` on admin auth | Wrong `AACTL_ADMIN_SECRET` | Restart the broker with the correct secret | |
| 241 | +| `Connection refused` | Broker not running | `./broker` or `docker compose up` | |
| 242 | +| App 5 returns empty events | Admin token expired | Re-run the aactl command or re-authenticate | |
| 243 | +| App 9 shows all `PASS` | Ceiling is too wide — all test scopes are allowed | Narrow the ceiling so `admin:revoke:*` and `read:logs:*` are outside it | |
0 commit comments