agent-authority 0.1.0

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 (85) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/LICENSE +21 -0
  3. package/QUICKSTART.md +91 -0
  4. package/README.md +553 -0
  5. package/dist/a2a.d.ts +73 -0
  6. package/dist/a2a.d.ts.map +1 -0
  7. package/dist/a2a.js +117 -0
  8. package/dist/a2a.js.map +1 -0
  9. package/dist/audit.d.ts +12 -0
  10. package/dist/audit.d.ts.map +1 -0
  11. package/dist/audit.js +52 -0
  12. package/dist/audit.js.map +1 -0
  13. package/dist/behalf.d.ts +173 -0
  14. package/dist/behalf.d.ts.map +1 -0
  15. package/dist/behalf.js +475 -0
  16. package/dist/behalf.js.map +1 -0
  17. package/dist/capability.d.ts +56 -0
  18. package/dist/capability.d.ts.map +1 -0
  19. package/dist/capability.js +176 -0
  20. package/dist/capability.js.map +1 -0
  21. package/dist/cli.d.ts +3 -0
  22. package/dist/cli.d.ts.map +1 -0
  23. package/dist/cli.js +273 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/control-plane.d.ts +57 -0
  26. package/dist/control-plane.d.ts.map +1 -0
  27. package/dist/control-plane.js +332 -0
  28. package/dist/control-plane.js.map +1 -0
  29. package/dist/crypto.d.ts +68 -0
  30. package/dist/crypto.d.ts.map +1 -0
  31. package/dist/crypto.js +105 -0
  32. package/dist/crypto.js.map +1 -0
  33. package/dist/errors.d.ts +25 -0
  34. package/dist/errors.d.ts.map +1 -0
  35. package/dist/errors.js +40 -0
  36. package/dist/errors.js.map +1 -0
  37. package/dist/index.d.ts +35 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +34 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/lint.d.ts +17 -0
  42. package/dist/lint.d.ts.map +1 -0
  43. package/dist/lint.js +75 -0
  44. package/dist/lint.js.map +1 -0
  45. package/dist/mandate.d.ts +99 -0
  46. package/dist/mandate.d.ts.map +1 -0
  47. package/dist/mandate.js +141 -0
  48. package/dist/mandate.js.map +1 -0
  49. package/dist/mcp-server.d.ts +26 -0
  50. package/dist/mcp-server.d.ts.map +1 -0
  51. package/dist/mcp-server.js +111 -0
  52. package/dist/mcp-server.js.map +1 -0
  53. package/dist/mcp.d.ts +63 -0
  54. package/dist/mcp.d.ts.map +1 -0
  55. package/dist/mcp.js +123 -0
  56. package/dist/mcp.js.map +1 -0
  57. package/dist/persist.d.ts +51 -0
  58. package/dist/persist.d.ts.map +1 -0
  59. package/dist/persist.js +150 -0
  60. package/dist/persist.js.map +1 -0
  61. package/dist/quickstart.d.ts +63 -0
  62. package/dist/quickstart.d.ts.map +1 -0
  63. package/dist/quickstart.js +171 -0
  64. package/dist/quickstart.js.map +1 -0
  65. package/dist/remote.d.ts +93 -0
  66. package/dist/remote.d.ts.map +1 -0
  67. package/dist/remote.js +120 -0
  68. package/dist/remote.js.map +1 -0
  69. package/dist/seal.d.ts +12 -0
  70. package/dist/seal.d.ts.map +1 -0
  71. package/dist/seal.js +96 -0
  72. package/dist/seal.js.map +1 -0
  73. package/dist/store.d.ts +119 -0
  74. package/dist/store.d.ts.map +1 -0
  75. package/dist/store.js +139 -0
  76. package/dist/store.js.map +1 -0
  77. package/dist/types.d.ts +173 -0
  78. package/dist/types.d.ts.map +1 -0
  79. package/dist/types.js +17 -0
  80. package/dist/types.js.map +1 -0
  81. package/llms.txt +106 -0
  82. package/package.json +107 -0
  83. package/schemas/capability.schema.json +14 -0
  84. package/schemas/mandate.schema.json +68 -0
  85. package/vectors/mandate-vector.json +63 -0
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Core type definitions for Behalf.
3
+ *
4
+ * A Mandate is a signed, scoped, time-bound capability token that proves who
5
+ * authorized what, within which limits, and through which chain of agents.
6
+ *
7
+ * The token is a biscuit-style Ed25519 signature chain of blocks. Each block
8
+ * carries restrictions (caveats) and publishes a fresh public key; the next
9
+ * block is signed by the matching private key, which the holder must possess to
10
+ * attenuate (append a narrowing block) or to authorize (prove possession of the
11
+ * terminal key). The intersection rule is enforced structurally — every cap
12
+ * caveat must be satisfied — so a downstream agent can only ever shrink
13
+ * authority, never widen it, and a holder cannot present a truncated prefix of
14
+ * its chain because it lacks that prefix's terminal key.
15
+ */
16
+ /** Restriction attached to a mandate. */
17
+ export type Caveat = {
18
+ t: "principal";
19
+ principal: string;
20
+ } | {
21
+ t: "agent";
22
+ agent: string;
23
+ } | {
24
+ t: "cap";
25
+ can: string[];
26
+ } | {
27
+ t: "expires";
28
+ at: number;
29
+ } | {
30
+ t: "id";
31
+ id: string;
32
+ }
33
+ /**
34
+ * Cryptographic agent identity binding (SVID-style): the holder must, at
35
+ * authorize, also prove possession of the private key for this public key.
36
+ * Conjunctive — every `agentKey` caveat must be satisfied — so a thief who
37
+ * holds the credential cannot append their own binding to bypass it.
38
+ */
39
+ | {
40
+ t: "agentKey";
41
+ key: string;
42
+ };
43
+ /**
44
+ * One link in the delegation chain: a set of restrictions plus the public key
45
+ * (`nextPub`) that authorizes whoever signs the *next* block.
46
+ */
47
+ export interface Block {
48
+ caveats: Caveat[];
49
+ /** base64url SPKI Ed25519 public key for the next block's signature. */
50
+ nextPub: string;
51
+ }
52
+ /** Wire form of a mandate — exactly what gets serialized/transmitted. */
53
+ export interface MandateToken {
54
+ /** Format version. */
55
+ v: 2;
56
+ /** Root identifier (stable across the whole delegation chain). */
57
+ id: string;
58
+ /** Ordered blocks: root grant first, narrowings appended after. */
59
+ blocks: Block[];
60
+ /** Per-block Ed25519 signatures (base64url). sigs[i] signs blocks[i]. */
61
+ sigs: string[];
62
+ /** Issuer (root) public key, base64url SPKI — pin this to establish trust. */
63
+ rootPub: string;
64
+ }
65
+ /**
66
+ * Proof of possession of a mandate's terminal key, presented at authorize time
67
+ * to prove the bearer is the legitimate tail of the chain (not a truncated
68
+ * prefix). `ts` is when it was minted (checked for freshness); `sig` is the
69
+ * Ed25519 signature over the proof message.
70
+ */
71
+ export interface Proof {
72
+ ts: number;
73
+ sig: string;
74
+ /**
75
+ * Optional verifier-issued single-use nonce (from `engine.challenge()`).
76
+ * When present it is bound into the signature and consumed on use, giving
77
+ * true anti-replay; without it, replay is bounded only by `proofSkewMs`.
78
+ */
79
+ nonce?: string;
80
+ /**
81
+ * Agent-identity signatures over the same proof message, one per agent key the
82
+ * holder controls. At authorize, every `agentKey` caveat in the chain must be
83
+ * satisfied by one of these (conjunctive), proving the presenter is the bound
84
+ * agent — not merely a possessor of the credential.
85
+ */
86
+ agentSigs?: string[];
87
+ }
88
+ /** Options for {@link Behalf.grant}. */
89
+ export interface GrantOptions {
90
+ /** The human/org authorizing the agent. */
91
+ principal: string;
92
+ /** The agent being authorized. */
93
+ agent: string;
94
+ /** Capabilities granted (capability grammar strings). */
95
+ can: string[];
96
+ /** Lifetime, e.g. "1h", "10m", "30s", or milliseconds as a number. */
97
+ expiresIn: string | number;
98
+ /**
99
+ * Cryptographically bind this grant to an agent identity (the agent's public
100
+ * key, base64url). The holder must then prove possession of the matching
101
+ * private key at authorize — see the `agentKey` caveat.
102
+ */
103
+ bindAgent?: string;
104
+ }
105
+ /** Options for {@link Mandate.attenuate}. */
106
+ export interface AttenuateOptions {
107
+ /** Narrowed capability set — must be a subset/narrowing of the parent's. */
108
+ can?: string[];
109
+ /** New (shorter) lifetime relative to now. Never extends past the parent. */
110
+ expiresIn?: string | number;
111
+ /** Optionally re-bind to a specific sub-agent. */
112
+ agent?: string;
113
+ /**
114
+ * Add a cryptographic agent-identity binding (the agent's public key,
115
+ * base64url). Conjunctive with any inherited `agentKey` caveats, so it can
116
+ * only ever add a requirement, never remove one.
117
+ */
118
+ bindAgent?: string;
119
+ }
120
+ /** The decision fields of an audit record, before it is sealed into the chain. */
121
+ export type AuditFields = Pick<AuditEntry, "mandateId" | "chain" | "action" | "decision" | "reason" | "issuer">;
122
+ /** A single hash-chained audit record (integrity-chained; see README Limitations). */
123
+ export interface AuditEntry {
124
+ seq: number;
125
+ ts: number;
126
+ mandateId: string;
127
+ /** Issuer (root) public key of the mandate, for per-tenant scoping. */
128
+ issuer?: string;
129
+ /** Full chain of ids this token belongs to (root → leaf). */
130
+ chain: string[];
131
+ action: string;
132
+ decision: "allow" | "deny";
133
+ reason?: string;
134
+ /** Hash of the previous entry (hash chain). */
135
+ prevHash: string;
136
+ /** sha256 over (prevHash + canonical entry body). */
137
+ hash: string;
138
+ }
139
+ /** Result of verifying audit-log integrity. */
140
+ export interface AuditIntegrity {
141
+ ok: boolean;
142
+ /** seq of the first broken entry, if any. */
143
+ brokenAt?: number;
144
+ }
145
+ /**
146
+ * A signed anchor over the audit log's head. Because the head hash commits to
147
+ * every prior entry, a stored checkpoint makes later tail-deletion or rewrites
148
+ * detectable — something the unkeyed hash chain alone cannot do.
149
+ */
150
+ export interface AuditCheckpoint {
151
+ /** seq of the head entry at checkpoint time (-1 for an empty log). */
152
+ seq: number;
153
+ /** Head entry's hash (the genesis hash for an empty log). */
154
+ hash: string;
155
+ ts: number;
156
+ /** Public key (base64url) of the engine that signed this checkpoint. */
157
+ signer: string;
158
+ /** Ed25519 signature over the canonical {seq, hash, ts} message. */
159
+ sig: string;
160
+ }
161
+ /** A just-in-time consent request tracked by the control plane. */
162
+ export interface ConsentRecord {
163
+ id: string;
164
+ agent: string;
165
+ capability: string;
166
+ context?: Record<string, unknown>;
167
+ /** Tenant issuer this request belongs to (set when created with a tenant token). */
168
+ issuer?: string;
169
+ status: "pending" | "approved" | "denied" | "expired";
170
+ createdAt: number;
171
+ decidedAt?: number;
172
+ }
173
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Core type definitions for Behalf.
3
+ *
4
+ * A Mandate is a signed, scoped, time-bound capability token that proves who
5
+ * authorized what, within which limits, and through which chain of agents.
6
+ *
7
+ * The token is a biscuit-style Ed25519 signature chain of blocks. Each block
8
+ * carries restrictions (caveats) and publishes a fresh public key; the next
9
+ * block is signed by the matching private key, which the holder must possess to
10
+ * attenuate (append a narrowing block) or to authorize (prove possession of the
11
+ * terminal key). The intersection rule is enforced structurally — every cap
12
+ * caveat must be satisfied — so a downstream agent can only ever shrink
13
+ * authority, never widen it, and a holder cannot present a truncated prefix of
14
+ * its chain because it lacks that prefix's terminal key.
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
package/llms.txt ADDED
@@ -0,0 +1,106 @@
1
+ # Behalf
2
+
3
+ > The reference implementation of agent authority. Behalf gives any AI agent a
4
+ > verifiable, scoped, revocable identity and delegation chain in five verbs.
5
+ > MIT-licensed and AI-legible: read this, then use it directly.
6
+
7
+ Everything is one primitive — a **Mandate**: a signed, scoped, time-bound
8
+ capability token proving who authorized what, within which limits, and through
9
+ which chain of agents. There is exactly one canonical way to do each thing.
10
+
11
+ ## The five verbs (TypeScript)
12
+
13
+ ```ts
14
+ import { Behalf } from "agent-authority";
15
+
16
+ // 1. GRANT — a principal authorizes an agent: scoped, capped, short-lived
17
+ const mandate = await Behalf.grant({
18
+ principal: user.id,
19
+ agent: "research-agent",
20
+ can: ["read:calendar", "spend:usd<=50"],
21
+ expiresIn: "1h",
22
+ });
23
+
24
+ // 2. AUTHORIZE — prove authority before acting (throws if denied)
25
+ await mandate.authorize("spend:usd=20");
26
+
27
+ // 3. ATTENUATE — hand a NARROWED mandate to a sub-agent; can only shrink scope
28
+ const child = mandate.attenuate({ can: ["read:calendar"], expiresIn: "10m" });
29
+
30
+ // 4. REVOKE — kill a mandate and its whole downstream chain, instantly
31
+ await Behalf.revoke(mandate.id);
32
+
33
+ // 5. AUDIT — every authorize() already wrote a hash-chained record
34
+ const trail = await Behalf.audit(mandate.id);
35
+ ```
36
+
37
+ Five verbs: grant, authorize, attenuate, revoke, audit. Do not add a sixth.
38
+
39
+ ## MCP middleware (secure a whole agent in ~6 lines)
40
+
41
+ ```ts
42
+ import { withBehalf } from "agent-authority/mcp";
43
+
44
+ const server = withBehalf(myMcpServer, {
45
+ policy: {
46
+ send_email: "write:email",
47
+ read_calendar: "read:calendar",
48
+ transfer_funds: (args) => `spend:usd<=${args.amount}`,
49
+ },
50
+ onDenied: "throw", // or "prompt" for just-in-time user consent
51
+ });
52
+ ```
53
+
54
+ Pass the caller's mandate on the call context: `server.callTool(name, args, { mandate })`.
55
+
56
+ ## Capability grammar
57
+
58
+ ```
59
+ read:calendar # simple capability
60
+ write:repo/acme-app # resource-scoped (path segments)
61
+ spend:usd<=50 # quantitative limit
62
+ send:email rate<=10/h # rate limit
63
+ * # wildcard (discouraged; lint warns)
64
+ ```
65
+
66
+ When authorizing, name a concrete amount: `spend:usd=20` is checked against the
67
+ grant's `spend:usd<=50`.
68
+
69
+ ## Rules an agent must follow
70
+
71
+ - Use only the five verbs. `attenuate()` only ever narrows (throws `WideningError`
72
+ on a wider or direction-flipped request).
73
+ - Effective authority = the principal's grant ∩ every narrowing along the chain.
74
+ A compromised middle agent can never widen scope.
75
+ - A mandate is a biscuit-style Ed25519 signature chain. **Authorizing requires
76
+ proving possession of the chain's terminal key**, so a serialized token is not
77
+ a usable bearer credential and a holder cannot truncate its chain to regain a
78
+ parent's scope. `mandate.authorize(action)` does this in-process. Across a
79
+ boundary, present `mandate.prove(action)` and verify with
80
+ `engine.authorize(token, action, proof)` (or use `agent-authority/a2a`).
81
+ - For an advisory "would this scope allow X?" check (no possession), use
82
+ `engine.inspect(token, action)`.
83
+ - Verification is offline (signature + scope + expiry + possession), public-key
84
+ only. Revocation and the shared rate cap need a network check.
85
+ - Prefer short `expiresIn` and the tightest `can` that still does the job.
86
+
87
+ ## Discovery tools (MCP)
88
+
89
+ `agent-authority/mcp` exposes `request_mandate`, `present_mandate`, and `check_authority`
90
+ (advisory) so any agent can obtain and reason about authority natively. Get them
91
+ via `behalfMcpTools()`, or run the standalone server: `node dist/mcp-server.js`.
92
+
93
+ ## Quickstarts & schemas
94
+
95
+ - `agent-authority quickstart <surface>` wires it into Claude Code, Cursor, Copilot,
96
+ Gemini, GPT, or any AI (see QUICKSTART.md).
97
+ - Typed schemas: /schemas/mandate.schema.json, /schemas/capability.schema.json.
98
+
99
+ ## What maps to the standard underneath
100
+
101
+ - Mandate ↔ Agentic JWT / capability tokens (IBCT-style)
102
+ - attenuate() + proof-of-possession ↔ biscuit-style attenuation & sealing
103
+ - principal → agent grant ↔ OAuth 2.1 On-Behalf-Of / token exchange (RFC 8693)
104
+ - agent identity ↔ SPIFFE / SVID
105
+ - audit record ↔ provenance / non-repudiation records
106
+ - transport ↔ MCP + A2A authorization layers
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "agent-authority",
3
+ "version": "0.1.0",
4
+ "description": "Authorization for AI agents: verifiable, scoped, revocable capability tokens (mandates) with attenuable delegation, for MCP and A2A. The reference implementation of agent authority — zero-dependency TypeScript & Python.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "sideEffects": false,
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/novaai0401-ui/agent-authority.git"
11
+ },
12
+ "homepage": "https://github.com/novaai0401-ui/agent-authority#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/novaai0401-ui/agent-authority/issues"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public",
18
+ "provenance": true
19
+ },
20
+ "keywords": [
21
+ "agent-authority",
22
+ "agent",
23
+ "authority",
24
+ "authorization",
25
+ "ai-agents",
26
+ "agentic",
27
+ "llm",
28
+ "delegation",
29
+ "capability",
30
+ "capability-tokens",
31
+ "capability-based-security",
32
+ "least-privilege",
33
+ "mandate",
34
+ "macaroons",
35
+ "biscuit",
36
+ "oauth",
37
+ "on-behalf-of",
38
+ "spiffe",
39
+ "ed25519",
40
+ "revocation",
41
+ "mcp",
42
+ "mcp-server",
43
+ "a2a",
44
+ "tool-calling",
45
+ "permissions"
46
+ ],
47
+ "files": [
48
+ "dist",
49
+ "schemas",
50
+ "vectors",
51
+ "llms.txt",
52
+ "QUICKSTART.md",
53
+ "CHANGELOG.md"
54
+ ],
55
+ "bin": {
56
+ "agent-authority": "./dist/cli.js",
57
+ "agent-authority-mcp": "./dist/mcp-server.js",
58
+ "agent-authority-control-plane": "./dist/control-plane.js"
59
+ },
60
+ "exports": {
61
+ ".": {
62
+ "types": "./dist/index.d.ts",
63
+ "import": "./dist/index.js"
64
+ },
65
+ "./mcp": {
66
+ "types": "./dist/mcp.d.ts",
67
+ "import": "./dist/mcp.js"
68
+ },
69
+ "./a2a": {
70
+ "types": "./dist/a2a.d.ts",
71
+ "import": "./dist/a2a.js"
72
+ },
73
+ "./server": {
74
+ "types": "./dist/mcp-server.d.ts",
75
+ "import": "./dist/mcp-server.js"
76
+ },
77
+ "./control-plane": {
78
+ "types": "./dist/control-plane.d.ts",
79
+ "import": "./dist/control-plane.js"
80
+ },
81
+ "./remote": {
82
+ "types": "./dist/remote.d.ts",
83
+ "import": "./dist/remote.js"
84
+ },
85
+ "./llms.txt": "./llms.txt"
86
+ },
87
+ "scripts": {
88
+ "build": "tsc -p tsconfig.json",
89
+ "test": "tsc -p tsconfig.test.json && node scripts/run-tests.mjs",
90
+ "test:interop": "npm run build && node scripts/interop.mjs",
91
+ "typecheck": "tsc -p tsconfig.json --noEmit",
92
+ "prepublishOnly": "npm run build && npm test",
93
+ "example:data-access": "node dist-test/examples/data-access-agent.js",
94
+ "example:spend": "node dist-test/examples/spend-limited-agent.js",
95
+ "example:delegation": "node dist-test/examples/two-agent-delegation.js",
96
+ "example:a2a": "node dist-test/examples/a2a-delegation.js",
97
+ "example:control-plane": "node dist-test/examples/control-plane.js",
98
+ "examples": "tsc -p tsconfig.test.json && node scripts/run-examples.mjs"
99
+ },
100
+ "engines": {
101
+ "node": ">=18"
102
+ },
103
+ "devDependencies": {
104
+ "@types/node": "^25.9.2",
105
+ "typescript": "^5.4.0"
106
+ }
107
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://behalf.dev/schemas/capability.schema.json",
4
+ "title": "Behalf Capability",
5
+ "description": "A capability string in the Behalf grammar: <verb>:<resource>[<op><amount>] [rate<op><value>/<unit>]. Examples: read:calendar, write:repo/acme-app, spend:usd<=50, send:email rate<=10/h, * (wildcard, discouraged).",
6
+ "type": "string",
7
+ "pattern": "^(\\*|[^:\\s]+:[^<>=\\s]+((<=|>=|<|>|=)[0-9]*\\.?[0-9]+)?(\\s+rate(<=|>=|<|>|=)[0-9]*\\.?[0-9]+(/[smhd])?)*)$",
8
+ "examples": [
9
+ "read:calendar",
10
+ "write:repo/acme-app",
11
+ "spend:usd<=50",
12
+ "send:email rate<=10/h"
13
+ ]
14
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://behalf.dev/schemas/mandate.schema.json",
4
+ "title": "Behalf Mandate Token",
5
+ "description": "The wire form of a Mandate: a signed, scoped, time-bound capability token. Macaroon-style: a root identifier plus ordered caveats bound by an HMAC chain. Holders may append narrowing caveats (attenuation) but can never widen.",
6
+ "type": "object",
7
+ "required": ["v", "id", "caveats", "sig"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "v": { "const": 1, "description": "Token format version." },
11
+ "id": {
12
+ "type": "string",
13
+ "description": "Root identifier, stable across the whole delegation chain."
14
+ },
15
+ "caveats": {
16
+ "type": "array",
17
+ "description": "Ordered restrictions; root grant first, narrowings appended.",
18
+ "items": { "$ref": "#/$defs/caveat" }
19
+ },
20
+ "sig": {
21
+ "type": "string",
22
+ "pattern": "^[0-9a-f]+$",
23
+ "description": "HMAC chain signature over (id, caveats...). Hex."
24
+ }
25
+ },
26
+ "$defs": {
27
+ "caveat": {
28
+ "oneOf": [
29
+ {
30
+ "type": "object",
31
+ "required": ["t", "principal"],
32
+ "additionalProperties": false,
33
+ "properties": { "t": { "const": "principal" }, "principal": { "type": "string" } }
34
+ },
35
+ {
36
+ "type": "object",
37
+ "required": ["t", "agent"],
38
+ "additionalProperties": false,
39
+ "properties": { "t": { "const": "agent" }, "agent": { "type": "string" } }
40
+ },
41
+ {
42
+ "type": "object",
43
+ "required": ["t", "can"],
44
+ "additionalProperties": false,
45
+ "properties": {
46
+ "t": { "const": "cap" },
47
+ "can": {
48
+ "type": "array",
49
+ "items": { "$ref": "https://behalf.dev/schemas/capability.schema.json" }
50
+ }
51
+ }
52
+ },
53
+ {
54
+ "type": "object",
55
+ "required": ["t", "at"],
56
+ "additionalProperties": false,
57
+ "properties": { "t": { "const": "expires" }, "at": { "type": "integer", "description": "Expiry, ms since epoch." } }
58
+ },
59
+ {
60
+ "type": "object",
61
+ "required": ["t", "id"],
62
+ "additionalProperties": false,
63
+ "properties": { "t": { "const": "id" }, "id": { "type": "string" } }
64
+ }
65
+ ]
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "description": "Cross-language Behalf test vector. Verify with trust=[pubkey] and a clock fixed at proof.ts: engine.authorize(token, action, proof) must ALLOW; tampering any field must DENY. Proof message: behalf-pop\\n{id}\\n{sigs,}\\n{ts}\\n{action}\\n{nonce-or-empty}.",
3
+ "action": "spend:usd=10",
4
+ "pubkey": "h4tQPvHL33UEH-y-vAbp37Q0DgCaUvKhNUb1RPITXBg",
5
+ "token": {
6
+ "v": 2,
7
+ "id": "fc05e43e-5299-4725-8912-20a525a54135",
8
+ "blocks": [
9
+ {
10
+ "caveats": [
11
+ {
12
+ "t": "principal",
13
+ "principal": "vector"
14
+ },
15
+ {
16
+ "t": "agent",
17
+ "agent": "root"
18
+ },
19
+ {
20
+ "t": "cap",
21
+ "can": [
22
+ "read:calendar",
23
+ "spend:usd<=50"
24
+ ]
25
+ },
26
+ {
27
+ "t": "expires",
28
+ "at": 1781270690715
29
+ }
30
+ ],
31
+ "nextPub": "DuqOtYTt-eMazEo0IRCEFK77rtMz0GVGgRGeUX3wBtE"
32
+ },
33
+ {
34
+ "caveats": [
35
+ {
36
+ "t": "cap",
37
+ "can": [
38
+ "spend:usd<=20"
39
+ ]
40
+ },
41
+ {
42
+ "t": "agent",
43
+ "agent": "sub"
44
+ },
45
+ {
46
+ "t": "id",
47
+ "id": "d067b7fe-02a9-46be-ab40-dbebeecea96e"
48
+ }
49
+ ],
50
+ "nextPub": "hJn-jjbxXzcow0tf-bnMuTa5EVFAEZO-k5B7qfa9Www"
51
+ }
52
+ ],
53
+ "sigs": [
54
+ "ncNFmqcb5omNijLf1d2KZk-vj-Kw5VTQDZluc6L1XHYcKC9KJlWiuNQNd9RLWV1TU8bs1TZo367RC3Q6VG4gDA",
55
+ "uFaNyCSQI6P2lRiyvykqTDyobZ2SKOvG8yetGzv0po9ee6oqn-2QeW0SFWxQRPnhWfj4xXwA_t6s1olF3X8dDQ"
56
+ ],
57
+ "rootPub": "h4tQPvHL33UEH-y-vAbp37Q0DgCaUvKhNUb1RPITXBg"
58
+ },
59
+ "proof": {
60
+ "ts": 1781267090717,
61
+ "sig": "bgzRquVLdMnQrFKgD0Sese6MbcRGXC_7dXWMVSV9F3EMT6LpfrCgH_YQABhVWpgvCqkX9z9ZJsrq_9OGPAioAg"
62
+ }
63
+ }