auramaxx 1.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +112 -0
  3. package/bin/aurawallet.js +121 -0
  4. package/docs/ADAPTERS.md +467 -0
  5. package/docs/API.md +2679 -0
  6. package/docs/APPS.md +198 -0
  7. package/docs/ARCHITECTURE.md +350 -0
  8. package/docs/AUTH.md +698 -0
  9. package/docs/BEST-PRACTICES.md +121 -0
  10. package/docs/CLI.md +61 -0
  11. package/docs/DEVELOPING-APPS.md +452 -0
  12. package/docs/EXTENSION.md +97 -0
  13. package/docs/JOBS.md +33 -0
  14. package/docs/MCP.md +76 -0
  15. package/docs/PROTOCOL.md +142 -0
  16. package/docs/SETUP.md +219 -0
  17. package/docs/WORKSPACE.md +672 -0
  18. package/docs/agent-auth.md +63 -0
  19. package/docs/aura-file.md +48 -0
  20. package/docs/credentials.md +53 -0
  21. package/docs/external/getting-started.md +65 -0
  22. package/docs/external/overview.md +45 -0
  23. package/docs/external/use-cases.md +48 -0
  24. package/docs/external/why-aura.md +35 -0
  25. package/docs/jobs/connect-agent.md +77 -0
  26. package/docs/jobs/migrate-from-dotenv.md +79 -0
  27. package/docs/jobs/recover-from-lockout.md +72 -0
  28. package/docs/jobs/secure-ci.md +63 -0
  29. package/docs/oauth2.md +42 -0
  30. package/docs/passkeys.md +60 -0
  31. package/docs/security.md +540 -0
  32. package/docs/specs/aura-open-protocol.md +61 -0
  33. package/docs/specs/aura-provider-plugin.md +24 -0
  34. package/docs/specs/aura-registry-model.md +31 -0
  35. package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
  36. package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
  37. package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
  38. package/docs/specs/fixtures/valid-basic.aura +4 -0
  39. package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
  40. package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
  41. package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
  42. package/docs/totp.md +40 -0
  43. package/docs/wallet/AI.md +508 -0
  44. package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
  45. package/docs/wallet/README.md +47 -0
  46. package/docs/wallet/STRATEGY.md +89 -0
  47. package/next.config.ts +21 -0
  48. package/package.json +151 -0
  49. package/postcss.config.mjs +8 -0
  50. package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
  51. package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
  52. package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
  53. package/prisma/migrations/migration_lock.toml +3 -0
  54. package/prisma/schema.prisma +447 -0
  55. package/public/logo-chevron.svg +31 -0
  56. package/public/logo-concentric.svg +31 -0
  57. package/public/logo-crosshatch.svg +39 -0
  58. package/public/logo-dashed.svg +39 -0
  59. package/public/logo-horizontal.svg +31 -0
  60. package/public/logo-m56.svg +64 -0
  61. package/public/logo.webp +0 -0
  62. package/scripts/add-app.js +245 -0
  63. package/scripts/init.sh +57 -0
  64. package/scripts/migrate-apikeys-to-credentials.ts +35 -0
  65. package/scripts/sandbox-agent-flow.sh +235 -0
  66. package/scripts/sandbox.sh +175 -0
  67. package/scripts/validate-job-docs.mjs +125 -0
  68. package/server/abi/SwapHelper.json +438 -0
  69. package/server/cli/approval.ts +447 -0
  70. package/server/cli/commands/app.ts +204 -0
  71. package/server/cli/commands/cron.ts +24 -0
  72. package/server/cli/commands/doctor.ts +1007 -0
  73. package/server/cli/commands/env.ts +456 -0
  74. package/server/cli/commands/init.ts +752 -0
  75. package/server/cli/commands/mcp.ts +125 -0
  76. package/server/cli/commands/restore.ts +314 -0
  77. package/server/cli/commands/shell-hook.ts +468 -0
  78. package/server/cli/commands/start.ts +62 -0
  79. package/server/cli/commands/status.ts +59 -0
  80. package/server/cli/commands/stop.ts +14 -0
  81. package/server/cli/commands/token.ts +180 -0
  82. package/server/cli/commands/unlock.ts +49 -0
  83. package/server/cli/commands/vault.ts +417 -0
  84. package/server/cli/index.ts +328 -0
  85. package/server/cli/lib/aura-parser.ts +64 -0
  86. package/server/cli/lib/credential-create.ts +74 -0
  87. package/server/cli/lib/credential-resolve.ts +254 -0
  88. package/server/cli/lib/dotenv-migrate.ts +116 -0
  89. package/server/cli/lib/dotenv-parser.ts +146 -0
  90. package/server/cli/lib/http.ts +91 -0
  91. package/server/cli/lib/init-steps.ts +76 -0
  92. package/server/cli/lib/local-agent-trust.ts +45 -0
  93. package/server/cli/lib/process.ts +136 -0
  94. package/server/cli/lib/prompt.ts +85 -0
  95. package/server/cli/lib/theme.ts +240 -0
  96. package/server/cli/socket.ts +570 -0
  97. package/server/cli/transport-client.ts +50 -0
  98. package/server/cron/index.ts +137 -0
  99. package/server/cron/job.ts +31 -0
  100. package/server/cron/jobs/balance-sync.ts +436 -0
  101. package/server/cron/jobs/incoming-scan.ts +506 -0
  102. package/server/cron/jobs/native-price.ts +70 -0
  103. package/server/cron/jobs/orphan-cleanup.ts +40 -0
  104. package/server/cron/jobs/strategy-runner.ts +175 -0
  105. package/server/cron/scheduler.ts +125 -0
  106. package/server/index.ts +406 -0
  107. package/server/lib/adapters/factory.ts +110 -0
  108. package/server/lib/adapters/index.ts +19 -0
  109. package/server/lib/adapters/router.ts +297 -0
  110. package/server/lib/adapters/telegram.ts +645 -0
  111. package/server/lib/adapters/types.ts +89 -0
  112. package/server/lib/adapters/webhook.ts +95 -0
  113. package/server/lib/address.ts +49 -0
  114. package/server/lib/agent-auth/contracts.ts +1194 -0
  115. package/server/lib/agent-profiles.ts +328 -0
  116. package/server/lib/ai.ts +285 -0
  117. package/server/lib/api-registry/contracts.ts +86 -0
  118. package/server/lib/api-registry/validation.ts +172 -0
  119. package/server/lib/apikey-migration.ts +189 -0
  120. package/server/lib/app-installer.ts +505 -0
  121. package/server/lib/app-tokens.ts +247 -0
  122. package/server/lib/auth.ts +314 -0
  123. package/server/lib/batch.ts +242 -0
  124. package/server/lib/cold.ts +874 -0
  125. package/server/lib/config.ts +381 -0
  126. package/server/lib/credential-access-audit.ts +85 -0
  127. package/server/lib/credential-access-policy.ts +110 -0
  128. package/server/lib/credential-health.ts +343 -0
  129. package/server/lib/credential-import.ts +487 -0
  130. package/server/lib/credential-scope.ts +87 -0
  131. package/server/lib/credential-shares.ts +190 -0
  132. package/server/lib/credential-transport.ts +342 -0
  133. package/server/lib/credential-vault.ts +77 -0
  134. package/server/lib/credentials.ts +333 -0
  135. package/server/lib/crypto.ts +8 -0
  136. package/server/lib/db.ts +15 -0
  137. package/server/lib/defaults.ts +366 -0
  138. package/server/lib/dex/index.ts +80 -0
  139. package/server/lib/dex/relay.ts +235 -0
  140. package/server/lib/dex/types.ts +59 -0
  141. package/server/lib/dex/uniswap.ts +370 -0
  142. package/server/lib/e2e-agent/artifacts.ts +36 -0
  143. package/server/lib/e2e-agent/contracts.ts +112 -0
  144. package/server/lib/e2e-agent/validation.ts +135 -0
  145. package/server/lib/encrypt.ts +128 -0
  146. package/server/lib/error.ts +20 -0
  147. package/server/lib/events.ts +205 -0
  148. package/server/lib/hot.ts +357 -0
  149. package/server/lib/key-fingerprint.ts +28 -0
  150. package/server/lib/logger.ts +331 -0
  151. package/server/lib/network.ts +137 -0
  152. package/server/lib/notifications.ts +219 -0
  153. package/server/lib/oauth2-refresh.ts +241 -0
  154. package/server/lib/oursecret.ts +54 -0
  155. package/server/lib/passkey-credential.ts +360 -0
  156. package/server/lib/passkey.ts +68 -0
  157. package/server/lib/permissions.ts +248 -0
  158. package/server/lib/pino.ts +24 -0
  159. package/server/lib/policy-preview.ts +138 -0
  160. package/server/lib/price.ts +338 -0
  161. package/server/lib/prices.ts +34 -0
  162. package/server/lib/project-scope.ts +239 -0
  163. package/server/lib/resolve-action.ts +427 -0
  164. package/server/lib/resolve.ts +36 -0
  165. package/server/lib/sessions.ts +632 -0
  166. package/server/lib/solana/connection.ts +26 -0
  167. package/server/lib/solana/jupiter.ts +128 -0
  168. package/server/lib/solana/transfer.ts +108 -0
  169. package/server/lib/solana/wallet.ts +136 -0
  170. package/server/lib/strategy/emits.ts +21 -0
  171. package/server/lib/strategy/engine.ts +1305 -0
  172. package/server/lib/strategy/executor.ts +115 -0
  173. package/server/lib/strategy/hook-context.ts +158 -0
  174. package/server/lib/strategy/hooks.ts +990 -0
  175. package/server/lib/strategy/index.ts +28 -0
  176. package/server/lib/strategy/installer.ts +305 -0
  177. package/server/lib/strategy/loader.ts +256 -0
  178. package/server/lib/strategy/message.ts +235 -0
  179. package/server/lib/strategy/repository.ts +218 -0
  180. package/server/lib/strategy/session-logger.ts +693 -0
  181. package/server/lib/strategy/sources.ts +288 -0
  182. package/server/lib/strategy/state.ts +189 -0
  183. package/server/lib/strategy/templates.ts +403 -0
  184. package/server/lib/strategy/tick.ts +404 -0
  185. package/server/lib/strategy/types.ts +230 -0
  186. package/server/lib/swap.ts +3 -0
  187. package/server/lib/temp.ts +86 -0
  188. package/server/lib/token-metadata.ts +86 -0
  189. package/server/lib/token-safety.ts +200 -0
  190. package/server/lib/token-search.ts +444 -0
  191. package/server/lib/totp.ts +194 -0
  192. package/server/lib/transactions.ts +123 -0
  193. package/server/lib/transport.ts +75 -0
  194. package/server/lib/txhistory/decoder.ts +262 -0
  195. package/server/lib/txhistory/enricher.ts +652 -0
  196. package/server/lib/txhistory/index.ts +391 -0
  197. package/server/lib/txhistory/signatures.ts +59 -0
  198. package/server/lib/verified-summary.ts +421 -0
  199. package/server/mcp/profile-policy.ts +30 -0
  200. package/server/mcp/server.ts +619 -0
  201. package/server/mcp/tools.ts +523 -0
  202. package/server/middleware/auth.ts +119 -0
  203. package/server/middleware/requestLogger.ts +84 -0
  204. package/server/routes/actions.ts +459 -0
  205. package/server/routes/adapters.ts +703 -0
  206. package/server/routes/addressbook.ts +113 -0
  207. package/server/routes/ai.ts +34 -0
  208. package/server/routes/apikeys.ts +295 -0
  209. package/server/routes/apps.ts +601 -0
  210. package/server/routes/auth.ts +457 -0
  211. package/server/routes/backup.ts +340 -0
  212. package/server/routes/batch.ts +270 -0
  213. package/server/routes/bookmarks.ts +162 -0
  214. package/server/routes/credential-shares.ts +198 -0
  215. package/server/routes/credential-vaults.ts +154 -0
  216. package/server/routes/credentials.ts +1290 -0
  217. package/server/routes/dashboard.ts +71 -0
  218. package/server/routes/defaults.ts +124 -0
  219. package/server/routes/fund.ts +229 -0
  220. package/server/routes/import.ts +352 -0
  221. package/server/routes/launch.ts +665 -0
  222. package/server/routes/lock.ts +54 -0
  223. package/server/routes/logs.ts +68 -0
  224. package/server/routes/nuke.ts +111 -0
  225. package/server/routes/passkey-credentials.ts +99 -0
  226. package/server/routes/passkey.ts +346 -0
  227. package/server/routes/portfolio.ts +217 -0
  228. package/server/routes/price.ts +63 -0
  229. package/server/routes/resolve.ts +31 -0
  230. package/server/routes/security.ts +45 -0
  231. package/server/routes/send-evm.ts +241 -0
  232. package/server/routes/send-solana.ts +281 -0
  233. package/server/routes/send.ts +178 -0
  234. package/server/routes/setup.ts +210 -0
  235. package/server/routes/strategy.ts +894 -0
  236. package/server/routes/swap-evm.ts +353 -0
  237. package/server/routes/swap-solana.ts +177 -0
  238. package/server/routes/swap.ts +356 -0
  239. package/server/routes/token.ts +247 -0
  240. package/server/routes/unlock.ts +403 -0
  241. package/server/routes/wallet-assets.ts +361 -0
  242. package/server/routes/wallet-transactions.ts +515 -0
  243. package/server/routes/wallet.ts +710 -0
  244. package/server/types.ts +146 -0
  245. package/skills/aurawallet/SKILL.md +739 -0
  246. package/skills/aurawallet-setup/SKILL.md +74 -0
  247. package/skills/security-review/SKILL.md +148 -0
  248. package/src/app/api/agent-requests/route.ts +30 -0
  249. package/src/app/api/apps/install/route.ts +126 -0
  250. package/src/app/api/apps/manifests/route.ts +16 -0
  251. package/src/app/api/apps/static/[...path]/route.ts +57 -0
  252. package/src/app/api/events/route.ts +92 -0
  253. package/src/app/api/page.tsx +212 -0
  254. package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
  255. package/src/app/api/workspace/[id]/apps/route.ts +81 -0
  256. package/src/app/api/workspace/[id]/export/route.ts +67 -0
  257. package/src/app/api/workspace/[id]/route.ts +168 -0
  258. package/src/app/api/workspace/auth.ts +34 -0
  259. package/src/app/api/workspace/config/route.ts +106 -0
  260. package/src/app/api/workspace/import/route.ts +127 -0
  261. package/src/app/api/workspace/route.ts +116 -0
  262. package/src/app/app/page.tsx +2122 -0
  263. package/src/app/apple-icon.png +0 -0
  264. package/src/app/docs/page.tsx +178 -0
  265. package/src/app/favicon.ico +0 -0
  266. package/src/app/globals.css +572 -0
  267. package/src/app/health/page.tsx +5 -0
  268. package/src/app/hello/page.tsx +15 -0
  269. package/src/app/icon.png +0 -0
  270. package/src/app/layout.tsx +34 -0
  271. package/src/app/page.tsx +986 -0
  272. package/src/app/providers.tsx +90 -0
  273. package/src/app/share/[token]/page.tsx +295 -0
  274. package/src/components/ChainSelector.tsx +144 -0
  275. package/src/components/HumanActionBar.tsx +695 -0
  276. package/src/components/NotificationDrawer.tsx +129 -0
  277. package/src/components/apps/AgentKeysApp.tsx +490 -0
  278. package/src/components/apps/App.tsx +153 -0
  279. package/src/components/apps/AppGrid.tsx +15 -0
  280. package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
  281. package/src/components/apps/DraggableApp.tsx +562 -0
  282. package/src/components/apps/IFrameApp.tsx +73 -0
  283. package/src/components/apps/LogsApp.tsx +360 -0
  284. package/src/components/apps/SendApp.tsx +394 -0
  285. package/src/components/apps/SetupWizardApp.tsx +1004 -0
  286. package/src/components/apps/SystemDefaultsApp.tsx +845 -0
  287. package/src/components/apps/ThirdPartyApp.tsx +428 -0
  288. package/src/components/apps/TokenApp.tsx +319 -0
  289. package/src/components/apps/TransactionsApp.tsx +438 -0
  290. package/src/components/apps/WalletDetailApp.tsx +1505 -0
  291. package/src/components/apps/index.ts +13 -0
  292. package/src/components/design-system/Button.tsx +53 -0
  293. package/src/components/design-system/ChainIndicator.tsx +65 -0
  294. package/src/components/design-system/ChainSelector.tsx +137 -0
  295. package/src/components/design-system/ConfirmationModal.tsx +106 -0
  296. package/src/components/design-system/ConfirmationPopover.tsx +81 -0
  297. package/src/components/design-system/Drawer.tsx +123 -0
  298. package/src/components/design-system/FilterDropdown.tsx +72 -0
  299. package/src/components/design-system/Modal.tsx +206 -0
  300. package/src/components/design-system/Popover.tsx +142 -0
  301. package/src/components/design-system/TextInput.tsx +85 -0
  302. package/src/components/design-system/Toggle.tsx +58 -0
  303. package/src/components/design-system/index.ts +11 -0
  304. package/src/components/docs/DocsThemeToggle.tsx +49 -0
  305. package/src/components/health/CredentialHealthDashboard.tsx +214 -0
  306. package/src/components/icons/ChainIcons.tsx +72 -0
  307. package/src/components/layout/AppStoreDrawer.tsx +369 -0
  308. package/src/components/layout/ContentArea.tsx +21 -0
  309. package/src/components/layout/TabBar.tsx +278 -0
  310. package/src/components/layout/WalletSidebar.tsx +1033 -0
  311. package/src/components/layout/index.ts +4 -0
  312. package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
  313. package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
  314. package/src/components/vault/ApiKeysConsole.tsx +1080 -0
  315. package/src/components/vault/AuditConsole.tsx +584 -0
  316. package/src/components/vault/CredentialDetail.tsx +455 -0
  317. package/src/components/vault/CredentialEmpty.tsx +55 -0
  318. package/src/components/vault/CredentialField.tsx +361 -0
  319. package/src/components/vault/CredentialForm.tsx +1212 -0
  320. package/src/components/vault/CredentialList.tsx +165 -0
  321. package/src/components/vault/CredentialRow.tsx +97 -0
  322. package/src/components/vault/CredentialShareModal.tsx +178 -0
  323. package/src/components/vault/CredentialVault.tsx +754 -0
  324. package/src/components/vault/CredentialWalletWidget.tsx +103 -0
  325. package/src/components/vault/ImportCredentialsModal.tsx +515 -0
  326. package/src/components/vault/LargeTypeModal.tsx +64 -0
  327. package/src/components/vault/PasswordGenerator.tsx +224 -0
  328. package/src/components/vault/TOTPDisplay.tsx +123 -0
  329. package/src/components/vault/VaultSidebar.tsx +413 -0
  330. package/src/components/vault/types.ts +54 -0
  331. package/src/context/AuthContext.tsx +337 -0
  332. package/src/context/PriceContext.tsx +113 -0
  333. package/src/context/ThemeContext.tsx +164 -0
  334. package/src/context/WebSocketContext.tsx +269 -0
  335. package/src/context/WorkspaceContext.tsx +668 -0
  336. package/src/hooks/index.ts +3 -0
  337. package/src/hooks/useAgentActions.ts +368 -0
  338. package/src/hooks/useBalance.ts +103 -0
  339. package/src/hooks/useBalances.ts +129 -0
  340. package/src/instrumentation.ts +12 -0
  341. package/src/lib/api.ts +449 -0
  342. package/src/lib/app-loader.ts +148 -0
  343. package/src/lib/app-registry.ts +178 -0
  344. package/src/lib/app-sdk.ts +157 -0
  345. package/src/lib/audit-console-adapter.ts +151 -0
  346. package/src/lib/auth-client.ts +75 -0
  347. package/src/lib/config.ts +74 -0
  348. package/src/lib/crypto.ts +112 -0
  349. package/src/lib/db.ts +21 -0
  350. package/src/lib/docs.ts +390 -0
  351. package/src/lib/events.ts +361 -0
  352. package/src/lib/pino.ts +24 -0
  353. package/src/lib/theme-handlers.ts +168 -0
  354. package/src/lib/theme.ts +351 -0
  355. package/src/lib/tokenData.ts +378 -0
  356. package/src/lib/vault-crypto.ts +129 -0
  357. package/src/lib/websocket-server.ts +302 -0
  358. package/src/lib/websocket-setup.ts +79 -0
  359. package/src/lib/wordlist.ts +2050 -0
  360. package/src/lib/workspace-handlers.ts +285 -0
  361. package/start.sh +80 -0
  362. package/tailwind.config.ts +99 -0
  363. package/tsconfig.json +42 -0
package/docs/AUTH.md ADDED
@@ -0,0 +1,698 @@
1
+ # Authentication & Permissions
2
+
3
+ This document describes the authentication system and permission model for AuraWallet.
4
+
5
+ ## For Agents
6
+
7
+ > **IMPORTANT**: If you're an agent, request a token via `POST /auth` and wait for human approval. You do NOT need an admin token - those are only for emergency/headless scenarios where a human is completely out of the loop.
8
+
9
+ ```bash
10
+ # 1. Request access (returns requestId + secret)
11
+ curl -X POST http://localhost:4242/auth \
12
+ -H "Content-Type: application/json" \
13
+ -d '{"agentId": "my-agent", "permissions": ["wallet:create:hot", "send:hot", "fund"]}'
14
+
15
+ # 2. Human approves in dashboard UI
16
+
17
+ # 3. Poll for your token
18
+ curl "http://localhost:4242/auth/<requestId>?secret=<secret>"
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Auth Flow Comparison
24
+
25
+ AuraWallet has multiple token flows for different scenarios. Use this table to pick the right one:
26
+
27
+ | Flow | Endpoint | Who Uses It | Approval | Token TTL | Use Case |
28
+ |------|----------|-------------|----------|-----------|----------|
29
+ | **Agent Request** | `POST /auth` | AI agents | Human approval required | Custom (default 1h) | Standard agent onboarding — agent requests access, human approves |
30
+ | **Human Unlock** | `POST /unlock` | Humans | Password (RSA-encrypted) + `pubkey` | 7 days | Unlock vault, get admin token for dashboard/API |
31
+ | **Direct Create** | `POST /actions/token` | Admins | Admin auth + `pubkey` | Custom | Emergency/headless — skip approval flow entirely |
32
+ | **Permission Upgrade** | `POST /auth/request-permissions` | Agents with token | Human approval required | Same as new token | Agent needs more permissions or wallet access |
33
+ | **Human Action** | `POST /actions` | Agents with `action:create` | Human approval required | Custom (default 60s) | Per-operation approval — scoped temp token for one action. Server generates verified summary from actual action params |
34
+
35
+ ### Which flow should I use?
36
+
37
+ - **I'm an AI agent connecting for the first time** → `POST /auth` (standard flow)
38
+ - **I'm a human unlocking the wallet** → `POST /unlock` (returns admin token)
39
+ - **I'm an agent and need to do something outside my permissions** → `POST /actions` (request approval for one action)
40
+ - **I'm an agent and need permanent permission upgrades** → `POST /auth/request-permissions`
41
+ - **I'm running a script/CI with no human** → `POST /actions/token` (requires admin token)
42
+
43
+ ### Token properties by flow
44
+
45
+ | Property | Agent Request | Human Unlock | Direct Create | Permission Upgrade | Human Action |
46
+ |----------|:---:|:---:|:---:|:---:|:---:|
47
+ | Spending limits | Yes | No | Yes | Yes | Yes |
48
+ | Wallet access grants | Yes | All | Yes | Yes | Yes |
49
+ | Survives restart | No | No | No | No | No |
50
+ | Revocable | Yes | Yes | Yes | Yes | Yes |
51
+ | Requires human | Yes | Self (password) | No (admin) | Yes | Yes |
52
+
53
+ ---
54
+
55
+ ## Overview
56
+
57
+ AuraWallet uses Bearer token authentication. Tokens are issued to agents after human approval and contain embedded permissions and spending limits.
58
+
59
+ **Key Security Properties:**
60
+ - Tokens are HMAC-signed with an in-memory `SIGNING_KEY`
61
+ - Server restart invalidates ALL tokens (new SIGNING_KEY generated)
62
+ - Spending limits are embedded in tokens and tracked in memory
63
+ - Admin tokens bypass all permission checks
64
+
65
+ ---
66
+
67
+ ## Token Types
68
+
69
+ ### Agent Token
70
+
71
+ Issued to AI agents after human approval. Contains specific permissions and limits.
72
+
73
+ ```typescript
74
+ interface AgentTokenPayload {
75
+ agentId: string; // Identifier for the agent
76
+ permissions: string[]; // Permission strings (see below)
77
+ exp: number; // Expiration timestamp (ms)
78
+
79
+ // Per-permission limits (optional)
80
+ // Plain number = legacy single-currency limit (ETH)
81
+ // Record<string, number> = per-currency limits keyed by native token address
82
+ limits?: {
83
+ fund?: number | Record<string, number>; // Limit for cold→hot transfers
84
+ send?: number | Record<string, number>; // Limit for sends (optional)
85
+ swap?: number | Record<string, number>; // Volume limit for swaps (optional)
86
+ };
87
+
88
+ // Wallet access grants
89
+ walletAccess?: string[]; // Additional wallet addresses this token can access
90
+ }
91
+ ```
92
+
93
+ ### Admin Token
94
+
95
+ Admin tokens are regular agent tokens with `admin:*` permission. Generated when wallet is unlocked via `POST /unlock`.
96
+
97
+ ```typescript
98
+ // Admin token is just an AgentTokenPayload with:
99
+ {
100
+ agentId: 'admin',
101
+ permissions: ['admin:*'],
102
+ exp: <7 days from creation>,
103
+ // ... no limits (admin has full access)
104
+ }
105
+ ```
106
+
107
+ **Key behaviors:**
108
+ - Multiple admin tokens can exist simultaneously (each unlock creates a new one)
109
+ - Admin tokens are revocable via `POST /actions/tokens/revoke`
110
+ - Locking the wallet does NOT auto-revoke tokens (but most admin ops require unlocked wallet)
111
+ - Server restart invalidates all tokens (including admin)
112
+
113
+ ---
114
+
115
+ ## Permissions Reference
116
+
117
+ ### Wallet Operations
118
+
119
+ | Permission | Description | Routes |
120
+ |------------|-------------|--------|
121
+ | `wallet:list` | List and view wallets | `GET /wallets`, `GET /wallets/transactions`, `GET /wallet/:address` |
122
+ | `wallet:create:hot` | Create hot wallets | `POST /wallet/create` (tier: hot) |
123
+ | `wallet:create:temp` | Create temp wallets | `POST /wallet/create` (tier: temp) |
124
+ | `wallet:rename` | Update wallet metadata | `POST /wallet/rename` |
125
+ | `wallet:export` | Export private keys | `POST /wallet/:address/export` |
126
+ | `wallet:tx:add` | Add manual transaction records | `POST /wallet/:address/transactions` |
127
+ | `wallet:asset:add` | Add tracked assets | `POST /wallet/:address/asset` |
128
+ | `wallet:asset:remove` | Remove tracked assets | `DELETE /wallet/:address/asset/:id` |
129
+
130
+ ### Transaction Operations
131
+
132
+ | Permission | Description | Routes |
133
+ |------------|-------------|--------|
134
+ | `send:hot` | Send from hot wallets | `POST /send` (from hot wallet) |
135
+ | `send:temp` | Send from temp wallets | `POST /send` (from temp wallet) |
136
+ | `swap` | Execute token swaps | `POST /swap` |
137
+ | `fund` | Transfer from cold to hot | `POST /fund` |
138
+ | `launch` | Execute token launches via Doppler | `POST /launch` |
139
+
140
+ ### API Key Operations
141
+
142
+ | Permission | Description | Routes |
143
+ |------------|-------------|--------|
144
+ | `apikey:get` | Read API keys | `GET /apikeys` |
145
+ | `apikey:set` | Create/update/delete API keys | `POST /apikeys`, `DELETE /apikeys/:id` |
146
+
147
+ ### Credential Vault Operations
148
+
149
+ | Permission | Description | Routes |
150
+ |------------|-------------|--------|
151
+ | `secret:read` | List credential metadata and read credential fields (encrypted to token pubkey) | `GET /credentials`, `GET /credentials/:id`, `POST /credentials/:id/read` |
152
+ | `secret:write` | Create, update, and delete credentials | `POST /credentials`, `PUT /credentials/:id`, `DELETE /credentials/:id` |
153
+
154
+ ### Credential Access Controls
155
+
156
+ Tokens with secret permissions can include `credentialAccess`:
157
+
158
+ - `read` / `write`: scope arrays (`*`, `vault:<id>`, `tag:<name>`, or specific credential IDs)
159
+ - `excludeFields`: remove sensitive field keys from read responses
160
+ - `ttl`: credential-read lifetime in seconds from token `iat`
161
+ - `maxReads`: maximum successful credential reads for the token
162
+
163
+ ### Agent Profiles (Policy Packs)
164
+
165
+ `POST /auth` and `POST /actions/token` support policy profile issuance:
166
+
167
+ - `profile` (required for profile mode): profile id (`observer`, `deploy-bot`, `rotation-bot`, `trader`)
168
+ - `profileVersion` (optional, default `v1`)
169
+ - `profileOverrides` (optional tighten-only constraints)
170
+
171
+ When `profile` is provided, profile policy becomes the source of truth for:
172
+
173
+ - `permissions`
174
+ - `credentialAccess`
175
+ - `ttl`
176
+
177
+ Response metadata includes:
178
+
179
+ - `profile`
180
+ - `effectivePolicyHash`
181
+ - `overrideDelta`
182
+ - `warnings`
183
+
184
+ #### Override constraints (fail-closed)
185
+
186
+ Profile overrides are **tighten-only**:
187
+
188
+ - `ttlSeconds`: must be positive and <= profile default
189
+ - `maxReads`: must be positive and <= profile default
190
+ - `readScopes` / `writeScopes`: must be subsets of profile scopes (no broadening)
191
+ - `excludeFields`: cannot remove profile-required exclusions (can only add)
192
+
193
+ Invalid profile ids/versions or unsafe overrides return stable profile error codes (for deterministic automation handling).
194
+
195
+ ### Mandatory `pubkey` on Token Minting
196
+
197
+ All token mint paths require a valid RSA public key (`pubkey` / `requestedPubkey`):
198
+
199
+ - `POST /unlock`
200
+ - `POST /unlock/:vaultId`
201
+ - `POST /setup`
202
+ - `POST /auth`
203
+ - `POST /actions/token`
204
+ - token-issuing approval flows (`POST /actions`, `POST /actions/:id/resolve`, `POST /auth/request-permissions`)
205
+
206
+ The server normalizes and stores this value on the token as `agentPubkey`. Credential reads (`POST /credentials/:id/read`) are encrypted to that key and never returned in plaintext.
207
+
208
+ ### Strategy Operations
209
+
210
+ | Permission | Description | Routes |
211
+ |------------|-------------|--------|
212
+ | `strategy:read` | View strategies and their state | `GET /strategies`, `GET /strategies/:id/config`, `GET /strategies/:id/state`, `GET /strategies/history` |
213
+ | `strategy:manage` | Enable/disable strategies, update config, approve intents/apps | `POST /strategies/:id/toggle`, `PUT /strategies/:id/config`, `POST /strategies/:id/approve`, `POST /strategies/reload`, `POST /apps/:id/approve`, `DELETE /apps/:id/approve` |
214
+
215
+ ### App Operations
216
+
217
+ | Permission | Description | Routes |
218
+ |------------|-------------|--------|
219
+ | `app:storage` | Read/write own app's storage and send messages (scoped by agentId). Auto-granted to all app tokens. | `GET /apps/:id/storage`, `GET /apps/:id/storage/:key`, `PUT /apps/:id/storage/:key`, `DELETE /apps/:id/storage/:key`, `POST /apps/:id/message` |
220
+ | `app:storage:all` | Read/write ANY app's storage (cross-app) | Same routes as `app:storage`, bypasses scope check |
221
+ | `app:accesskey` | Read API keys from app storage. Auto-granted to app tokens whose sources use `key` fields. | `GET /apps/:id/apikey/:keyName` |
222
+
223
+ **App token agentId prefixes:** App tokens use `app:<appId>` as their agentId (e.g., `app:tic-tac-toe`). Legacy strategy tokens use `strategy:<appId>`. The storage scope enforcement strips both prefixes when matching against the URL's `:appId` parameter.
224
+
225
+ ### Address Book & Bookmark Operations
226
+
227
+ | Permission | Description | Routes |
228
+ |------------|-------------|--------|
229
+ | `addressbook:write` | Create, update, and delete address labels | `POST /address-labels`, `DELETE /address-labels/:id` |
230
+ | `bookmark:write` | Create and delete token bookmarks (watchlist) | `POST /bookmarks`, `DELETE /bookmarks/:id` |
231
+
232
+ ### Action Operations
233
+
234
+ | Permission | Description | Routes |
235
+ |------------|-------------|--------|
236
+ | `action:create` | Create human action requests (propose actions for approval), send notifications, and enable `request_human_action` tool in chat apps | `POST /actions` |
237
+
238
+ **Verified summaries:** When an agent creates an action request via `POST /actions`, the server generates a `verifiedSummary` from the actual pre-computed action parameters (endpoint, body, amounts, recipients). This is stored in the action metadata alongside the agent's `summary` text. The dashboard shows the server-generated one-liner and flags discrepancies (e.g., agent says "Swap 0.01 ETH" but the action body contains 10 ETH). Summary text is limited to 500 characters.
239
+
240
+ ### Compound Permissions
241
+
242
+ Compound permissions expand to multiple underlying permissions for convenience.
243
+
244
+ | Permission | Description | Expands To |
245
+ |------------|-------------|------------|
246
+ | `trade:all` | All trading permissions | `wallet:list`, `wallet:create:hot`, `wallet:create:temp`, `send:hot`, `send:temp`, `swap`, `fund`, `launch`, `apikey:get`, `strategy:read` |
247
+ | `wallet:write` | All wallet write operations | `wallet:create:hot`, `wallet:create:temp`, `wallet:rename`, `wallet:tx:add`, `wallet:asset:add`, `wallet:asset:remove` |
248
+
249
+ **Usage Example:**
250
+ ```typescript
251
+ // Instead of listing all trading permissions:
252
+ permissions: ['wallet:list', 'wallet:create:hot', 'send:hot', 'swap', 'fund', 'apikey:get']
253
+
254
+ // Use the compound permission:
255
+ permissions: ['trade:all']
256
+ ```
257
+
258
+ **Onboarding note:** `trade:all` does NOT include `apikey:set` or `adapter:manage`. Agents helping with first-time setup (configuring API keys, Telegram adapter) should request these explicitly:
259
+ ```typescript
260
+ permissions: ['trade:all', 'apikey:set', 'adapter:manage', 'action:create']
261
+ ```
262
+ See the [SKILL.md](../skills/aurawallet/SKILL.md) agent reference for the full onboarding guide.
263
+
264
+ ### UI/Workspace Operations
265
+
266
+ | Permission | Description | Routes |
267
+ |------------|-------------|--------|
268
+ | `workspace:modify` | Modify dashboard workspaces | WebSocket events (app:added, etc.) |
269
+
270
+ ### Admin
271
+
272
+ | Permission | Description | Routes |
273
+ |------------|-------------|--------|
274
+ | `admin:*` | Full access, bypass all checks | All routes |
275
+
276
+ ---
277
+
278
+ ## Route → Permission Mapping
279
+
280
+ | Route | Method | Permission Required | Notes |
281
+ |-------|--------|---------------------|-------|
282
+ | `/wallets` | GET | *public* | No auth required |
283
+ | `/wallet/:address` | GET | `wallet:list` | Optional auth, agents see only owned |
284
+ | `/wallet/create` | POST | `wallet:create:hot` or `wallet:create:temp` | Based on tier |
285
+ | `/wallet/rename` | POST | `wallet:rename` | + wallet access |
286
+ | `/wallet/:address/export` | POST | `wallet:export` | + wallet access + unlocked |
287
+ | `/wallets/transactions` | GET | `wallet:list` | Optional auth, agents see only owned |
288
+ | `/wallet/:address/transactions` | GET | `wallet:list` | Optional auth for own wallets; no auth for external addresses (on-chain fallback) |
289
+ | `/wallet/:address/transactions` | POST | `wallet:tx:add` | + wallet access |
290
+ | `/wallet/:address/assets` | GET | `wallet:list` | Optional auth, agents see only owned |
291
+ | `/wallet/:address/asset` | POST | `wallet:asset:add` | + wallet access |
292
+ | `/wallet/:address/asset/:id` | DELETE | `wallet:asset:remove` | + wallet access |
293
+ | `/send` | POST | `send:hot` or `send:temp` | Based on wallet tier |
294
+ | `/swap` | POST | `swap` | + wallet access |
295
+ | `/fund` | POST | `fund` | Limit enforced |
296
+ | `/launch` | POST | `launch` | + wallet access |
297
+ | `/launch/collect-fees` | POST | *(any token)* | Permissionless on-chain; wallet access for gas |
298
+ | `/launch/:addr/collect-fees` | POST | *(any token)* | Permissionless on-chain; wallet access for gas |
299
+ | `/auth/connect` | GET | *public* | Get server public key for password encryption |
300
+ | `/auth` | POST | *public* | Request token (`pubkey` required) |
301
+ | `/auth/:id` | GET | *public* | Poll for token |
302
+ | `/auth/validate` | POST | *any valid token* | Validate token |
303
+ | `/apikeys` | GET | `apikey:get` or `trade:all` | List all API keys |
304
+ | `/apikeys` | POST | `apikey:set` | Create/update API key |
305
+ | `/apikeys/validate` | POST | `apikey:set` | Validate API key against external service |
306
+ | `/apikeys/:id` | DELETE | `apikey:set` | Delete API key |
307
+ | `/unlock` | GET | *public* | Self-contained HTML unlock page (browser-based) |
308
+ | `/unlock` | POST | *public* | Unlock primary vault and mint admin token (`pubkey` required) |
309
+ | `/unlock/:vaultId` | POST | *public* | Unlock specific vault and mint admin token (`pubkey` required) |
310
+ | `/lock` | POST | `admin:*` | Locks ALL vaults. Admin only |
311
+ | `/lock/:vaultId` | POST | `admin:*` | Lock a specific vault. Admin only |
312
+ | `/vaults/credential` | GET | `admin:*` | List credential vaults |
313
+ | `/vaults/credential` | POST | `admin:*` | Create credential vault |
314
+ | `/vaults/credential/:id/lock` | POST | `admin:*` | Lock credential vault |
315
+ | `/vaults/credential/:id` | DELETE | `admin:*` | Delete credential vault + credentials |
316
+ | `/credentials` | GET | `secret:read` or `admin:*` | List credential metadata (scope filtered) |
317
+ | `/credentials` | POST | `secret:write` or `admin:*` | Create credential |
318
+ | `/credentials/:id` | GET | `secret:read` or `admin:*` | Get credential metadata |
319
+ | `/credentials/:id` | PUT | `secret:write` or `admin:*` | Update credential |
320
+ | `/credentials/:id` | DELETE | `secret:write` or `admin:*` | Delete credential |
321
+ | `/credentials/:id/read` | POST | `secret:read` or `admin:*` | Read credential (encrypted to `agentPubkey`) |
322
+ | `/setup/vault` | POST | `admin:*` | Create additional vault. Requires unlocked primary |
323
+ | `/setup/vault/import` | POST | `admin:*` | Import vault from seed. Requires unlocked primary |
324
+ | `/setup/vaults` | GET | *public* | List all vaults and their status |
325
+ | `/export-seed` | GET/POST | `admin:*` | Export seed phrase. Optional `vaultId` param |
326
+ | `/actions` | POST | `action:create` | Create human action request |
327
+ | `/actions/token` | POST | `admin:*` | Direct token creation (`pubkey` required) |
328
+ | `/actions/:id/resolve` | POST | `admin:*` | Approve/reject pending action |
329
+ | `/actions/tokens` | GET | `admin:*` | List all tokens |
330
+ | `/actions/tokens/revoke` | POST | `admin:*` or own token | Revoke a token |
331
+ | `/nuke` | POST | `admin:*` | Admin only |
332
+ | `/defaults` | GET | `admin:*` | List all system defaults |
333
+ | `/defaults/:key` | PATCH | `admin:*` | Update a system default |
334
+ | `/defaults/reset` | POST | `admin:*` | Reset system default(s) to seed values |
335
+ | `/ai/status` | GET | `admin:*` | AI provider status and availability |
336
+ | `/adapters` | GET | `adapter:manage` | List configured adapters |
337
+ | `/adapters` | POST | `adapter:manage` | Add/update adapter config |
338
+ | `/adapters/:type` | DELETE | `adapter:manage` | Remove adapter config |
339
+ | `/adapters/test` | POST | `adapter:manage` | Send test message through adapter |
340
+ | `/adapters/restart` | POST | `adapter:manage` | Restart approval router |
341
+ | `/address-labels` | GET | *any token or admin* | List all address labels |
342
+ | `/address-labels` | POST | `addressbook:write` | Create/update address label |
343
+ | `/address-labels/:id` | DELETE | `addressbook:write` | Delete address label |
344
+ | `/bookmarks` | GET | *any token or admin* | List bookmarked tokens |
345
+ | `/bookmarks` | POST | `bookmark:write` | Create token bookmark |
346
+ | `/bookmarks/:id` | DELETE | `bookmark:write` | Delete bookmark |
347
+ | `/health` | GET | *public* | No auth required |
348
+ | `/price/:address` | GET | *public* | Token price lookup |
349
+ | `/token/search` | GET | *public* | Search tokens by ticker/name |
350
+ | `/token/safety/:address` | GET | *public* | Token safety report (GoPlusLabs) |
351
+ | `/token/holders/:address` | GET | *public* | Top holders for a token |
352
+ | `/token/:tokenAddress/balance/:walletAddress` | GET | *public* | On-chain token balance for any address |
353
+ | `/batch` | POST | *public* | Batch multiple API calls with dependency chaining (auth per-sub-request) |
354
+ | `/strategies` | GET | `strategy:read` | List all strategies |
355
+ | `/strategies/:id/toggle` | POST | `strategy:manage` | Enable/disable strategy |
356
+ | `/strategies/:id/config` | GET | `strategy:read` | Get effective config |
357
+ | `/strategies/:id/config` | PUT | `strategy:manage` | Update config overrides |
358
+ | `/strategies/:id/approve` | POST | `strategy:manage` | Approve/reject intents |
359
+ | `/strategies/:id/state` | GET | `strategy:read` | Get strategy state (debug) |
360
+ | `/strategies/history` | GET | `strategy:read` | Strategy action history |
361
+ | `/strategies/reload` | POST | `strategy:manage` | Hot-reload from disk |
362
+ | `/apps/:id/storage` | GET | `app:storage` | List all storage keys |
363
+ | `/apps/:id/storage/:key` | GET | `app:storage` | Get storage value |
364
+ | `/apps/:id/storage/:key` | PUT | `app:storage` | Set storage value |
365
+ | `/apps/:id/storage/:key` | DELETE | `app:storage` | Delete storage key |
366
+ | `/apps/:id/apikey/:keyName` | GET | `app:accesskey` | Get API key from app storage |
367
+ | `/apps/:id/message` | POST | `app:storage` | Send message to app AI (scoped) |
368
+ | `/apps/:id/reload` | POST | `admin:*` | Hot-reload app token after install |
369
+ | `/apps/:id/approve` | POST | `strategy:manage` | Approve app permissions |
370
+ | `/apps/:id/approve` | DELETE | `strategy:manage` | Revoke app approval |
371
+ ---
372
+
373
+ ## Token Lifecycle
374
+
375
+ ```
376
+ ┌─────────────────────────────────────────────────────────────────┐
377
+ │ 1. Agent requests token │
378
+ │ POST /auth { agentId, permissions, limits, ttl, pubkey } │
379
+ │ → Returns requestId + secret │
380
+ ├─────────────────────────────────────────────────────────────────┤
381
+ │ 2. Human approves via UI or API │
382
+ │ POST /actions/:id/resolve { approved: true } │
383
+ │ → Token signed with SIGNING_KEY │
384
+ ├─────────────────────────────────────────────────────────────────┤
385
+ │ 3. Agent polls for token │
386
+ │ GET /auth/:requestId?secret=XXX │
387
+ │ → Returns signed token │
388
+ ├─────────────────────────────────────────────────────────────────┤
389
+ │ 4. Agent uses token │
390
+ │ Authorization: Bearer <token> │
391
+ │ → Validated against SIGNING_KEY │
392
+ │ → Spending tracked in memory │
393
+ ├─────────────────────────────────────────────────────────────────┤
394
+ │ 5. Agent requests permission upgrade (optional) │
395
+ │ POST /auth/request-permissions { requestedPermissions, requestedPubkey, ... } │
396
+ │ → Creates permission_update pending request │
397
+ │ → Human approves → poll for new token (same flow as step 3) │
398
+ ├─────────────────────────────────────────────────────────────────┤
399
+ │ 6. Token invalidation │
400
+ │ - Server restart (new SIGNING_KEY) - ALL tokens invalid │
401
+ │ - Human revokes: POST /actions/tokens/revoke │
402
+ │ - Token expires (exp timestamp) │
403
+ │ NOTE: Locking wallet does NOT invalidate tokens │
404
+ └─────────────────────────────────────────────────────────────────┘
405
+ ```
406
+
407
+ ---
408
+
409
+ ## External Approval Channels
410
+
411
+ In addition to the Dashboard UI and CLI terminal, approvals can flow through external channels (Telegram, Discord, webhooks) via the adapter system. All channels converge on the same `POST /actions/:id/resolve` endpoint.
412
+
413
+ See [docs/ADAPTERS.md](./ADAPTERS.md) for configuration, built-in adapters, and how to build custom adapters.
414
+
415
+ ---
416
+
417
+ ## Wallet Access Model
418
+
419
+ Tokens can access wallets they own OR wallets explicitly granted via `walletAccess`:
420
+
421
+ ```typescript
422
+ // Token can access wallet if:
423
+ // 1. Token created the wallet (tokenHash matches), OR
424
+ // 2. Wallet address is in token's walletAccess array
425
+
426
+ function tokenCanAccessWallet(tokenHash, walletAccess, address): boolean
427
+ ```
428
+
429
+ | Action | Who Can Do It |
430
+ |--------|---------------|
431
+ | Create hot wallet | Agent with `wallet:create:hot` permission |
432
+ | Send from wallet | Token that owns it OR has it in `walletAccess` |
433
+ | Export private key | Token owner OR admin with unlocked wallet |
434
+ | List wallets | Token sees owned wallets, admin sees all |
435
+
436
+ ---
437
+
438
+ ## Spending Limits
439
+
440
+ Limits are only enforced on `/fund` (cold→hot transfers):
441
+
442
+ ```typescript
443
+ // Token has embedded limits
444
+ {
445
+ limits: {
446
+ fund: 1.0, // Max 1 ETH from cold wallet
447
+ send: null, // No limit on sends (optional)
448
+ swap: null // No limit on swaps (optional)
449
+ }
450
+ }
451
+
452
+ // Spending tracked in memory per token
453
+ sessions.get(tokenHash) = {
454
+ token: AgentTokenPayload,
455
+ spent: 0,
456
+ spentByType: {
457
+ fund: 0.5, // Already used 0.5 of 1.0 ETH fund limit
458
+ send: 0,
459
+ swap: 0
460
+ }
461
+ }
462
+ ```
463
+
464
+ **Key Points:**
465
+ - `/fund` limit is the primary control (cold wallet access)
466
+ - `/send` has NO limit by default - agents spend freely from their hot wallets
467
+ - Limits are tamper-proof (embedded in HMAC-signed token)
468
+ - Server restart resets all spending (new sessions Map)
469
+
470
+ ---
471
+
472
+ ## API Keys
473
+
474
+ AuraWallet stores API keys as encrypted credential-vault entries (`type: "apikey"`). Legacy `ApiKey` DB rows are migrated/synced for compatibility, and `/apikeys` is served through the credential vault path.
475
+
476
+ ### Get All API Keys
477
+
478
+ ```bash
479
+ curl http://localhost:4242/apikeys \
480
+ -H "Authorization: Bearer <token>"
481
+ ```
482
+
483
+ Returns:
484
+ ```json
485
+ {
486
+ "success": true,
487
+ "apiKeys": [
488
+ {
489
+ "id": "...",
490
+ "service": "alchemy",
491
+ "name": "default",
492
+ "keyMasked": "abc1****3xyz",
493
+ "createdAt": "2026-02-03T..."
494
+ }
495
+ ]
496
+ }
497
+ ```
498
+
499
+ ### Create/Update API Key
500
+
501
+ ```bash
502
+ curl -X POST http://localhost:4242/apikeys \
503
+ -H "Authorization: Bearer <token>" \
504
+ -H "Content-Type: application/json" \
505
+ -d '{"service": "alchemy", "name": "default", "key": "your-api-key"}'
506
+ ```
507
+
508
+ Requires `apikey:set` permission.
509
+
510
+ ### Delete API Key
511
+
512
+ ```bash
513
+ curl -X DELETE http://localhost:4242/apikeys/<id> \
514
+ -H "Authorization: Bearer <token>"
515
+ ```
516
+
517
+ Requires `apikey:set` permission.
518
+
519
+ ### Validate API Key
520
+
521
+ ```bash
522
+ curl -X POST http://localhost:4242/apikeys/validate \
523
+ -H "Authorization: Bearer <token>" \
524
+ -H "Content-Type: application/json" \
525
+ -d '{"service": "alchemy", "key": "your-api-key"}'
526
+ ```
527
+
528
+ Validates an API key against its external service before saving. Requires `apikey:set` permission.
529
+
530
+ **Supported services:**
531
+ - `alchemy` — Sends `eth_blockNumber` JSON-RPC call. Valid if response contains a block number.
532
+ - `anthropic` — Sends minimal request to Messages API. 200 or 429 (rate-limited) = valid, 401 = invalid.
533
+ - `adapter:telegram` — Calls Telegram Bot API `getMe`. Returns `{ valid: true, info: { botUsername } }` on success.
534
+
535
+ All external calls have a 5-second timeout. Returns `{ valid: false, error: "Validation timed out" }` on timeout.
536
+
537
+ ### Test Adapter
538
+
539
+ ```bash
540
+ curl -X POST http://localhost:4242/adapters/test \
541
+ -H "Authorization: Bearer <token>" \
542
+ -H "Content-Type: application/json" \
543
+ -d '{"type": "telegram"}'
544
+ ```
545
+
546
+ Sends a test message through a configured adapter. Requires `adapter:manage` permission.
547
+
548
+ **Supported types:**
549
+ - `telegram` — Reads bot token and chat ID from DB, sends a test message via Telegram Bot API. Returns 404 if token or chat ID not configured.
550
+ - `webhook` — Reads webhook URL from adapter config, POSTs `{ type: "test", data: {}, timestamp }`. Returns 404 if URL not configured.
551
+
552
+ **Response:**
553
+ ```json
554
+ { "success": true }
555
+ ```
556
+
557
+ ---
558
+
559
+ ## Authentication Header
560
+
561
+ ```http
562
+ Authorization: Bearer <token>
563
+ ```
564
+
565
+ Example:
566
+ ```bash
567
+ curl http://localhost:4242/wallets \
568
+ -H "Authorization: Bearer eyJhZ2VudElkIjoibXktYm90IiwicGVybWlzc2..."
569
+ ```
570
+
571
+ ---
572
+
573
+ ## Error Responses
574
+
575
+ | Error | HTTP Status | Meaning |
576
+ |-------|-------------|---------|
577
+ | `Authentication required` | 401 | No token provided |
578
+ | `Invalid or expired token` | 401 | Bad signature or expired |
579
+ | `Token has been revoked` | 401 | Human revoked the token |
580
+ | `Insufficient permissions` | 403 | Token lacks required permission |
581
+ | `Token does not have access to this wallet` | 403 | Not owner, not in walletAccess |
582
+ | `Admin access required` | 403 | Route requires admin token |
583
+ | `Amount exceeds remaining spending limit` | 403 | Fund limit exceeded |
584
+ | `Cold wallet must be unlocked` | 401 | Need human to unlock first |
585
+
586
+ ---
587
+
588
+ ## Encrypted Password Transport
589
+
590
+ Passwords for `/unlock` and `/setup` are encrypted before transmission using RSA-OAEP. This protects against local interception by malware or other processes.
591
+
592
+ ### Flow
593
+
594
+ ```
595
+ ┌─────────────────────────────────────────────────────────────────┐
596
+ │ Server startup │
597
+ │ → Generate ephemeral RSA keypair (private key in memory) │
598
+ ├─────────────────────────────────────────────────────────────────┤
599
+ │ Frontend unlock/setup │
600
+ │ 1. GET /auth/connect → { publicKey: "-----BEGIN PUBLIC..." } │
601
+ │ 2. Encrypt password with RSA-OAEP using Web Crypto API │
602
+ │ 3. Generate caller RSA keypair (local) │
603
+ │ 4. POST /unlock → { encrypted: "base64...", pubkey: "..." } │
604
+ ├─────────────────────────────────────────────────────────────────┤
605
+ │ Server │
606
+ │ 1. Decrypt with private key → plaintext password │
607
+ │ 2. Normal unlock/setup flow │
608
+ │ 3. Return result (admin token on unlock) │
609
+ ├─────────────────────────────────────────────────────────────────┤
610
+ │ Server restart │
611
+ │ → New RSA keypair generated │
612
+ │ → Old cached public keys become invalid │
613
+ │ → Frontend auto-refetches on decryption failure │
614
+ └─────────────────────────────────────────────────────────────────┘
615
+ ```
616
+
617
+ The server also provides a built-in unlock page at `GET /unlock` that handles the encryption flow automatically in the browser — no frontend build required. **This is a fallback for headless environments.** When the dashboard (`http://localhost:4747/app`) is available, prefer directing users there instead.
618
+
619
+ ### Security Properties
620
+
621
+ - RSA private key never leaves server memory
622
+ - Keypair regenerates on restart (aligns with existing security model)
623
+ - RSA-OAEP provides semantic security (same plaintext → different ciphertext)
624
+ - Passwords never appear in plaintext over HTTP
625
+
626
+ ### Usage (Frontend)
627
+
628
+ ```typescript
629
+ import { unlockWallet, setupWallet } from '@/lib/api';
630
+
631
+ // These functions handle encryption automatically
632
+ const result = await unlockWallet(password);
633
+ const result = await setupWallet(password);
634
+ ```
635
+
636
+ ---
637
+
638
+ ## Security Best Practices
639
+
640
+ 1. **Never expose ports to internet** - This is a local-only system
641
+ 2. **Store secrets securely** - The `secret` from `/auth` is needed to retrieve tokens
642
+ 3. **Use minimal permissions** - Request only the permissions you need
643
+ 4. **Handle token expiry** - Tokens expire, implement refresh logic
644
+ 5. **Expect restarts** - Server restart invalidates all tokens, this is intentional
645
+
646
+ ---
647
+
648
+ ## Note on Admin Tokens
649
+
650
+ > **IMPORTANT**: 99% of the time you just need an agent token via `POST /auth`. If the wallet is unlocked, agents can request tokens through the normal human-approval flow. You should NOT need an admin token.
651
+
652
+ Admin tokens are returned when unlocking the wallet via `/unlock`. In normal usage, **you should not need to use the admin token directly**. The dashboard UI handles authentication automatically.
653
+
654
+ Admin tokens are intended for:
655
+ - **Emergency access** - Recovering from UI issues or debugging
656
+ - **Headless/automated scenarios** - When running without a human in the loop at all (e.g., CI/CD, scripts)
657
+ - **API exploration** - Testing endpoints directly with curl
658
+
659
+ For regular human-supervised operation:
660
+ 1. Just use the dashboard UI - it manages tokens internally
661
+ 2. Agents should request tokens via `POST /auth` and wait for human approval
662
+ 3. No admin token is needed for normal agent workflows
663
+
664
+ ---
665
+
666
+ ## Agent Permission Tiers
667
+
668
+ The `agent-chat` app supports two permission tiers that control what the chat agent can do directly vs. what requires human approval.
669
+
670
+ ### Tiers
671
+
672
+ | Tier | Permissions | Behavior |
673
+ |------|-------------|----------|
674
+ | **admin** (default) | `admin:*` | Agent can call `/send`, `/swap`, `/fund`, etc. directly. No approval popups. |
675
+ | **restricted** | `wallet:list`, `action:create` | Agent can only view wallets and propose actions via `request_human_action`. All trades require human approval. |
676
+
677
+ ### Configuration
678
+
679
+ The tier is stored as the system default `permissions.agent_tier`. It can be set:
680
+
681
+ - **Dashboard Settings** → `DEFAULT_AGENT` section → Permission Tier toggle
682
+ - **Setup Wizard** → AI Agent step → Permission Level toggle
683
+ - **API**: `PATCH /defaults/permissions.agent_tier` with `{ "value": "admin" | "restricted" }`
684
+
685
+ ### How It Works
686
+
687
+ 1. When `createAppToken('agent-chat')` runs, it checks `permissions.agent_tier`
688
+ 2. If `admin` → the token gets `['admin:*']` permissions (full access)
689
+ 3. If `restricted` → the token keeps the app's declared permissions (`wallet:list`, `action:create`)
690
+ 4. Only the `agent-chat` app is affected — all other apps keep their own permissions
691
+
692
+ ### Token Refresh on Tier Change
693
+
694
+ When `permissions.agent_tier` changes (via `PATCH /defaults`), the system automatically:
695
+ 1. Revokes the existing `agent-chat` app token
696
+ 2. Creates a new token with the updated permissions
697
+
698
+ This happens via an `onDefaultChanged` listener, so the change takes effect immediately without server restart.