agents-chain 0.0.1
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.
- package/README.md +145 -0
- package/dist/audit/audit-log.d.ts +44 -0
- package/dist/audit/audit-log.d.ts.map +1 -0
- package/dist/audit/audit-log.js +88 -0
- package/dist/audit/audit-log.js.map +1 -0
- package/dist/auth/token-builder.d.ts +32 -0
- package/dist/auth/token-builder.d.ts.map +1 -0
- package/dist/auth/token-builder.js +38 -0
- package/dist/auth/token-builder.js.map +1 -0
- package/dist/auth/token-verifier.d.ts +37 -0
- package/dist/auth/token-verifier.d.ts.map +1 -0
- package/dist/auth/token-verifier.js +86 -0
- package/dist/auth/token-verifier.js.map +1 -0
- package/dist/chain.d.ts +36 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +90 -0
- package/dist/chain.js.map +1 -0
- package/dist/crypto/ed25519.d.ts +63 -0
- package/dist/crypto/ed25519.d.ts.map +1 -0
- package/dist/crypto/ed25519.js +118 -0
- package/dist/crypto/ed25519.js.map +1 -0
- package/dist/crypto/utils.d.ts +18 -0
- package/dist/crypto/utils.d.ts.map +1 -0
- package/dist/crypto/utils.js +38 -0
- package/dist/crypto/utils.js.map +1 -0
- package/dist/errors/chain-error.d.ts +18 -0
- package/dist/errors/chain-error.d.ts.map +1 -0
- package/dist/errors/chain-error.js +22 -0
- package/dist/errors/chain-error.js.map +1 -0
- package/dist/identity/agent-identity.d.ts +33 -0
- package/dist/identity/agent-identity.d.ts.map +1 -0
- package/dist/identity/agent-identity.js +73 -0
- package/dist/identity/agent-identity.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.d.ts +6 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +25 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/memory/encrypted-store.d.ts +29 -0
- package/dist/memory/encrypted-store.d.ts.map +1 -0
- package/dist/memory/encrypted-store.js +102 -0
- package/dist/memory/encrypted-store.js.map +1 -0
- package/dist/memory/jti-cache.d.ts +22 -0
- package/dist/memory/jti-cache.d.ts.map +1 -0
- package/dist/memory/jti-cache.js +43 -0
- package/dist/memory/jti-cache.js.map +1 -0
- package/dist/types/audit.d.ts +16 -0
- package/dist/types/audit.d.ts.map +1 -0
- package/dist/types/audit.js +2 -0
- package/dist/types/audit.js.map +1 -0
- package/dist/types/chain.d.ts +19 -0
- package/dist/types/chain.d.ts.map +1 -0
- package/dist/types/chain.js +2 -0
- package/dist/types/chain.js.map +1 -0
- package/dist/types/identity.d.ts +35 -0
- package/dist/types/identity.d.ts.map +1 -0
- package/dist/types/identity.js +3 -0
- package/dist/types/identity.js.map +1 -0
- package/dist/wrappers/anthropic-wrapper.d.ts +31 -0
- package/dist/wrappers/anthropic-wrapper.d.ts.map +1 -0
- package/dist/wrappers/anthropic-wrapper.js +97 -0
- package/dist/wrappers/anthropic-wrapper.js.map +1 -0
- package/dist/wrappers/openai-wrapper.d.ts +34 -0
- package/dist/wrappers/openai-wrapper.d.ts.map +1 -0
- package/dist/wrappers/openai-wrapper.js +106 -0
- package/dist/wrappers/openai-wrapper.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# agents-chain
|
|
2
|
+
|
|
3
|
+
Lightweight identity, authentication, and audit layer for AI agent SDKs.
|
|
4
|
+
|
|
5
|
+
Wrap your OpenAI or Anthropic client with `agents-chain` to get:
|
|
6
|
+
|
|
7
|
+
- **Ed25519 key-pair identity** per agent instance
|
|
8
|
+
- **JWT-based capability tokens** — every API call is signed and verified
|
|
9
|
+
- **Encrypted in-memory audit log** — AES-256-GCM, queryable at runtime
|
|
10
|
+
- **Zero network calls** — everything runs locally, no external service required
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install agents-chain
|
|
18
|
+
# or
|
|
19
|
+
pnpm add agents-chain
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> Requires Node.js 18+
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
### OpenAI
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { AgentsChain } from 'agents-chain';
|
|
32
|
+
import OpenAI from 'openai';
|
|
33
|
+
|
|
34
|
+
const chain = await AgentsChain.create({
|
|
35
|
+
agentName: 'summarizer',
|
|
36
|
+
hostname: 'my-app',
|
|
37
|
+
capabilities: ['chat.completion'],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const ai = chain.openai(new OpenAI({ apiKey: process.env.OPENAI_API_KEY }));
|
|
41
|
+
|
|
42
|
+
const response = await ai.chat.completions.create({
|
|
43
|
+
model: 'gpt-4o',
|
|
44
|
+
messages: [{ role: 'user', content: 'Summarize the water cycle in one sentence.' }],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log(response.choices[0].message.content);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Anthropic
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { AgentsChain } from 'agents-chain';
|
|
54
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
55
|
+
|
|
56
|
+
const chain = await AgentsChain.create({
|
|
57
|
+
agentName: 'classifier',
|
|
58
|
+
hostname: 'my-app',
|
|
59
|
+
capabilities: ['messages.create'],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const ai = chain.anthropic(new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }));
|
|
63
|
+
|
|
64
|
+
const response = await ai.messages.create({
|
|
65
|
+
model: 'claude-sonnet-4-6',
|
|
66
|
+
max_tokens: 256,
|
|
67
|
+
messages: [{ role: 'user', content: 'Classify this text as positive or negative: "I love it!"' }],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
console.log(response.content[0]);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const chain = await AgentsChain.create({
|
|
79
|
+
agentName: string; // Human-readable name for this agent
|
|
80
|
+
hostname: string; // Used to build the agentId: "<hostname>-agent-<32hex>"
|
|
81
|
+
capabilities: string[]; // List of capability strings this agent is allowed to use
|
|
82
|
+
encryptionKey?: string; // Optional 64-char hex (32-byte) AES-256-GCM key.
|
|
83
|
+
// Omit to generate a random key per session.
|
|
84
|
+
// Provide to persist and reload audit logs across restarts.
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Audit log
|
|
91
|
+
|
|
92
|
+
Every API call through a wrapped client is recorded in an encrypted in-memory log.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
// Get all entries (decrypted)
|
|
96
|
+
const entries = chain.getAuditLog();
|
|
97
|
+
|
|
98
|
+
// Full snapshot with metadata
|
|
99
|
+
const snapshot = chain.exportAudit();
|
|
100
|
+
// { agentId, entries, exportedAt }
|
|
101
|
+
|
|
102
|
+
// Summary counts
|
|
103
|
+
const stats = chain.getStats();
|
|
104
|
+
// { agentId, agentName, hostname, totalCalls, successfulCalls, deniedCalls, errorCalls, registeredAt }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Each `AuditEntry` contains:
|
|
108
|
+
|
|
109
|
+
| Field | Type | Description |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `id` | `string` | Unique entry ID |
|
|
112
|
+
| `agentId` | `string` | The agent that made the call |
|
|
113
|
+
| `capability` | `string` | Capability used |
|
|
114
|
+
| `result` | `"success" \| "denied" \| "error"` | Outcome |
|
|
115
|
+
| `timestamp` | `number` | Unix ms |
|
|
116
|
+
| `meta` | `Record<string, unknown>` | Provider-specific metadata |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Identity & crypto utilities
|
|
121
|
+
|
|
122
|
+
Low-level utilities are exported if you need direct access:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import {
|
|
126
|
+
generateKeyPair,
|
|
127
|
+
exportPublicKeyJwk,
|
|
128
|
+
exportPrivateKeyJwk,
|
|
129
|
+
importPublicKeyJwk,
|
|
130
|
+
computeJwkThumbprint,
|
|
131
|
+
signJwt,
|
|
132
|
+
verifyJwtSignature,
|
|
133
|
+
decodeJwtUnsafe,
|
|
134
|
+
generateId,
|
|
135
|
+
generateAgentId,
|
|
136
|
+
base64UrlEncode,
|
|
137
|
+
base64UrlDecode,
|
|
138
|
+
} from 'agents-chain';
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
MIT — [brianmwangidev](https://www.npmjs.com/~brianmwangidev)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuditLog — append-only encrypted log of all capability call attempts.
|
|
3
|
+
*
|
|
4
|
+
* Every intercepted call (success, denied, or error) is recorded.
|
|
5
|
+
* Entries are encrypted with AES-256-GCM before being written to the store,
|
|
6
|
+
* so even if someone inspects process memory they see only ciphertext.
|
|
7
|
+
*
|
|
8
|
+
* The log is append-only within a session. There is no delete API.
|
|
9
|
+
*/
|
|
10
|
+
import type { EncryptedStore } from "../memory/encrypted-store.js";
|
|
11
|
+
import type { AuditEntry, AuditResult } from "../types/audit.js";
|
|
12
|
+
import type { VerifiedCallContext } from "../auth/token-verifier.js";
|
|
13
|
+
export type RecordDeniedOptions = {
|
|
14
|
+
agentId: string;
|
|
15
|
+
agentName: string;
|
|
16
|
+
hostname: string;
|
|
17
|
+
capability: string;
|
|
18
|
+
args: Record<string, unknown>;
|
|
19
|
+
reason: string;
|
|
20
|
+
jti: string;
|
|
21
|
+
};
|
|
22
|
+
export type RecordCallOptions = {
|
|
23
|
+
context: VerifiedCallContext;
|
|
24
|
+
args: Record<string, unknown>;
|
|
25
|
+
result: Exclude<AuditResult, "denied">;
|
|
26
|
+
durationMs: number;
|
|
27
|
+
errorMessage?: string;
|
|
28
|
+
};
|
|
29
|
+
export declare class AuditLog {
|
|
30
|
+
private readonly store;
|
|
31
|
+
constructor(store: EncryptedStore);
|
|
32
|
+
/** Record a denied capability call (before the SDK is touched). */
|
|
33
|
+
recordDenied(opts: RecordDeniedOptions): AuditEntry;
|
|
34
|
+
/** Record a completed capability call (success or error). */
|
|
35
|
+
recordCall(opts: RecordCallOptions): AuditEntry;
|
|
36
|
+
/** Return all decrypted audit entries for this session. */
|
|
37
|
+
getAll(): AuditEntry[];
|
|
38
|
+
/** Return entries filtered by result type. */
|
|
39
|
+
getByResult(result: AuditResult): AuditEntry[];
|
|
40
|
+
/** Return entries filtered by capability name. */
|
|
41
|
+
getByCapability(capability: string): AuditEntry[];
|
|
42
|
+
get count(): number;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=audit-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-log.d.ts","sourceRoot":"","sources":["../../src/audit/audit-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAIrE,MAAM,MAAM,mBAAmB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,qBAAa,QAAQ;IACL,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,cAAc;IAElD,mEAAmE;IACnE,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,UAAU;IAkBnD,6DAA6D;IAC7D,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU;IAkB/C,2DAA2D;IAC3D,MAAM,IAAI,UAAU,EAAE;IAItB,8CAA8C;IAC9C,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,EAAE;IAI9C,kDAAkD;IAClD,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE;IAIjD,IAAI,KAAK,IAAI,MAAM,CAElB;CACJ"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuditLog — append-only encrypted log of all capability call attempts.
|
|
3
|
+
*
|
|
4
|
+
* Every intercepted call (success, denied, or error) is recorded.
|
|
5
|
+
* Entries are encrypted with AES-256-GCM before being written to the store,
|
|
6
|
+
* so even if someone inspects process memory they see only ciphertext.
|
|
7
|
+
*
|
|
8
|
+
* The log is append-only within a session. There is no delete API.
|
|
9
|
+
*/
|
|
10
|
+
import { generateId } from "../crypto/utils.js";
|
|
11
|
+
const STORE_KEY_LOG = "audit:log";
|
|
12
|
+
export class AuditLog {
|
|
13
|
+
constructor(store) {
|
|
14
|
+
this.store = store;
|
|
15
|
+
}
|
|
16
|
+
/** Record a denied capability call (before the SDK is touched). */
|
|
17
|
+
recordDenied(opts) {
|
|
18
|
+
const entry = {
|
|
19
|
+
id: generateId("aud"),
|
|
20
|
+
agentId: opts.agentId,
|
|
21
|
+
agentName: opts.agentName,
|
|
22
|
+
hostname: opts.hostname,
|
|
23
|
+
capability: opts.capability,
|
|
24
|
+
args: sanitizeArgs(opts.args),
|
|
25
|
+
result: "denied",
|
|
26
|
+
denialReason: opts.reason,
|
|
27
|
+
jti: opts.jti,
|
|
28
|
+
timestamp: Date.now(),
|
|
29
|
+
durationMs: 0,
|
|
30
|
+
};
|
|
31
|
+
this.store.append(STORE_KEY_LOG, entry);
|
|
32
|
+
return entry;
|
|
33
|
+
}
|
|
34
|
+
/** Record a completed capability call (success or error). */
|
|
35
|
+
recordCall(opts) {
|
|
36
|
+
const entry = {
|
|
37
|
+
id: generateId("aud"),
|
|
38
|
+
agentId: opts.context.agentId,
|
|
39
|
+
agentName: opts.context.agentName,
|
|
40
|
+
hostname: opts.context.hostname,
|
|
41
|
+
capability: opts.context.capability,
|
|
42
|
+
args: sanitizeArgs(opts.args),
|
|
43
|
+
result: opts.result,
|
|
44
|
+
errorMessage: opts.errorMessage,
|
|
45
|
+
jti: opts.context.jti,
|
|
46
|
+
timestamp: Date.now(),
|
|
47
|
+
durationMs: opts.durationMs,
|
|
48
|
+
};
|
|
49
|
+
this.store.append(STORE_KEY_LOG, entry);
|
|
50
|
+
return entry;
|
|
51
|
+
}
|
|
52
|
+
/** Return all decrypted audit entries for this session. */
|
|
53
|
+
getAll() {
|
|
54
|
+
return this.store.get(STORE_KEY_LOG) ?? [];
|
|
55
|
+
}
|
|
56
|
+
/** Return entries filtered by result type. */
|
|
57
|
+
getByResult(result) {
|
|
58
|
+
return this.getAll().filter((e) => e.result === result);
|
|
59
|
+
}
|
|
60
|
+
/** Return entries filtered by capability name. */
|
|
61
|
+
getByCapability(capability) {
|
|
62
|
+
return this.getAll().filter((e) => e.capability === capability);
|
|
63
|
+
}
|
|
64
|
+
get count() {
|
|
65
|
+
return this.getAll().length;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Strip values that look like secrets from args before logging.
|
|
70
|
+
* Keys matching this pattern are replaced with "[REDACTED]".
|
|
71
|
+
*/
|
|
72
|
+
const SECRET_KEY_PATTERN = /(?:key|secret|token|password|auth|credential|bearer)/i;
|
|
73
|
+
function sanitizeArgs(args) {
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const [k, v] of Object.entries(args)) {
|
|
76
|
+
if (SECRET_KEY_PATTERN.test(k)) {
|
|
77
|
+
out[k] = "[REDACTED]";
|
|
78
|
+
}
|
|
79
|
+
else if (typeof v === "object" && v !== null && !Array.isArray(v)) {
|
|
80
|
+
out[k] = sanitizeArgs(v);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
out[k] = v;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=audit-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-log.js","sourceRoot":"","sources":["../../src/audit/audit-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenBuilder — creates signed agent+jwt tokens per capability call.
|
|
3
|
+
*
|
|
4
|
+
* Security design:
|
|
5
|
+
* - Every token is single-use: a fresh cryptographically random jti per call.
|
|
6
|
+
* - TTL is 60 seconds — minimal viable window for a synchronous SDK call.
|
|
7
|
+
* - The iss claim is the public key thumbprint (not a mutable name string).
|
|
8
|
+
* This ties the token cryptographically to the specific keypair.
|
|
9
|
+
* - The sub is the agentId (<hostname>-agent-<32hex>).
|
|
10
|
+
* - The aud is the capability name — a token for "chat.completion" cannot
|
|
11
|
+
* be presented as authorization for "embedding".
|
|
12
|
+
*/
|
|
13
|
+
import type { AgentIdentity } from "../identity/agent-identity.js";
|
|
14
|
+
export type AgentJwtClaims = {
|
|
15
|
+
iss: string;
|
|
16
|
+
sub: string;
|
|
17
|
+
aud: string;
|
|
18
|
+
iat: number;
|
|
19
|
+
exp: number;
|
|
20
|
+
jti: string;
|
|
21
|
+
hostname: string;
|
|
22
|
+
agentName: string;
|
|
23
|
+
};
|
|
24
|
+
export declare class TokenBuilder {
|
|
25
|
+
private readonly identity;
|
|
26
|
+
constructor(identity: AgentIdentity);
|
|
27
|
+
build(capability: string): Promise<{
|
|
28
|
+
token: string;
|
|
29
|
+
claims: AgentJwtClaims;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=token-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-builder.d.ts","sourceRoot":"","sources":["../../src/auth/token-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,MAAM,cAAc,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACrB,CAAC;AAIF,qBAAa,YAAY;IACT,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,aAAa;IAE9C,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,CAAA;KAAE,CAAC;CAkBtF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenBuilder — creates signed agent+jwt tokens per capability call.
|
|
3
|
+
*
|
|
4
|
+
* Security design:
|
|
5
|
+
* - Every token is single-use: a fresh cryptographically random jti per call.
|
|
6
|
+
* - TTL is 60 seconds — minimal viable window for a synchronous SDK call.
|
|
7
|
+
* - The iss claim is the public key thumbprint (not a mutable name string).
|
|
8
|
+
* This ties the token cryptographically to the specific keypair.
|
|
9
|
+
* - The sub is the agentId (<hostname>-agent-<32hex>).
|
|
10
|
+
* - The aud is the capability name — a token for "chat.completion" cannot
|
|
11
|
+
* be presented as authorization for "embedding".
|
|
12
|
+
*/
|
|
13
|
+
import { randomBytes } from "node:crypto";
|
|
14
|
+
import { signJwt } from "../crypto/ed25519.js";
|
|
15
|
+
import { base64UrlEncode } from "../crypto/utils.js";
|
|
16
|
+
const TOKEN_TTL_SECONDS = 60;
|
|
17
|
+
export class TokenBuilder {
|
|
18
|
+
constructor(identity) {
|
|
19
|
+
this.identity = identity;
|
|
20
|
+
}
|
|
21
|
+
async build(capability) {
|
|
22
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
23
|
+
const jti = base64UrlEncode(randomBytes(16));
|
|
24
|
+
const claims = {
|
|
25
|
+
iss: this.identity.thumbprint,
|
|
26
|
+
sub: this.identity.agentId,
|
|
27
|
+
aud: capability,
|
|
28
|
+
iat: nowSeconds,
|
|
29
|
+
exp: nowSeconds + TOKEN_TTL_SECONDS,
|
|
30
|
+
jti,
|
|
31
|
+
hostname: this.identity.registration.hostname,
|
|
32
|
+
agentName: this.identity.registration.agentName,
|
|
33
|
+
};
|
|
34
|
+
const token = await signJwt(claims, this.identity.privateKey, "agent+jwt");
|
|
35
|
+
return { token, claims };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=token-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-builder.js","sourceRoot":"","sources":["../../src/auth/token-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAcrD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B,MAAM,OAAO,YAAY;IACrB,YAA6B,QAAuB;QAAvB,aAAQ,GAAR,QAAQ,CAAe;IAAG,CAAC;IAExD,KAAK,CAAC,KAAK,CAAC,UAAkB;QAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QAE7C,MAAM,MAAM,GAAmB;YAC3B,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU;YAC7B,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO;YAC1B,GAAG,EAAE,UAAU;YACf,GAAG,EAAE,UAAU;YACf,GAAG,EAAE,UAAU,GAAG,iBAAiB;YACnC,GAAG;YACH,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ;YAC7C,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,SAAS;SAClD,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC7B,CAAC;CACJ"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenVerifier — verifies an agent+jwt token against the registered identity.
|
|
3
|
+
*
|
|
4
|
+
* Verification steps (must all pass before a capability call proceeds):
|
|
5
|
+
*
|
|
6
|
+
* 1. Decode JWT header — confirm typ = "agent+jwt"
|
|
7
|
+
* 2. Decode payload — extract iss (thumbprint), sub (agentId), aud (capability)
|
|
8
|
+
* 3. Verify sub matches the registered agentId — no foreign agents
|
|
9
|
+
* 4. Verify iss matches the registered public key thumbprint — no key swap
|
|
10
|
+
* 5. Verify aud matches the requested capability — scope-bound token
|
|
11
|
+
* 6. Import the registered public key and verify the Ed25519 signature
|
|
12
|
+
* 7. Check exp / iat temporal claims + clock skew
|
|
13
|
+
* 8. Check jti uniqueness (replay protection) via JtiCache
|
|
14
|
+
* 9. Verify the agent holds an active grant for the capability
|
|
15
|
+
*
|
|
16
|
+
* Steps 3-4 together prevent a valid token issued for a different agent
|
|
17
|
+
* (or different key) from being presented against this identity.
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentIdentity } from "../identity/agent-identity.js";
|
|
20
|
+
import type { JtiCache } from "../memory/jti-cache.js";
|
|
21
|
+
export type VerifiedCallContext = {
|
|
22
|
+
agentId: string;
|
|
23
|
+
agentName: string;
|
|
24
|
+
hostname: string;
|
|
25
|
+
capability: string;
|
|
26
|
+
jti: string;
|
|
27
|
+
iat: number;
|
|
28
|
+
exp: number;
|
|
29
|
+
};
|
|
30
|
+
export declare class TokenVerifier {
|
|
31
|
+
private readonly identity;
|
|
32
|
+
private readonly jtiCache;
|
|
33
|
+
constructor(identity: AgentIdentity, jtiCache: JtiCache);
|
|
34
|
+
verify(token: string, capability: string): Promise<VerifiedCallContext>;
|
|
35
|
+
private assertTemporal;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=token-verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-verifier.d.ts","sourceRoot":"","sources":["../../src/auth/token-verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAMvD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,aAAa;IAElB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,QAAQ;IAGjC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiE7E,OAAO,CAAC,cAAc;CAwBzB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenVerifier — verifies an agent+jwt token against the registered identity.
|
|
3
|
+
*
|
|
4
|
+
* Verification steps (must all pass before a capability call proceeds):
|
|
5
|
+
*
|
|
6
|
+
* 1. Decode JWT header — confirm typ = "agent+jwt"
|
|
7
|
+
* 2. Decode payload — extract iss (thumbprint), sub (agentId), aud (capability)
|
|
8
|
+
* 3. Verify sub matches the registered agentId — no foreign agents
|
|
9
|
+
* 4. Verify iss matches the registered public key thumbprint — no key swap
|
|
10
|
+
* 5. Verify aud matches the requested capability — scope-bound token
|
|
11
|
+
* 6. Import the registered public key and verify the Ed25519 signature
|
|
12
|
+
* 7. Check exp / iat temporal claims + clock skew
|
|
13
|
+
* 8. Check jti uniqueness (replay protection) via JtiCache
|
|
14
|
+
* 9. Verify the agent holds an active grant for the capability
|
|
15
|
+
*
|
|
16
|
+
* Steps 3-4 together prevent a valid token issued for a different agent
|
|
17
|
+
* (or different key) from being presented against this identity.
|
|
18
|
+
*/
|
|
19
|
+
import { verifyJwtSignature, decodeJwtUnsafe } from "../crypto/ed25519.js";
|
|
20
|
+
import { ChainAuthError } from "../errors/chain-error.js";
|
|
21
|
+
const CLOCK_SKEW_MS = 30000; // 30 seconds tolerance
|
|
22
|
+
const JWT_MAX_AGE_MS = 60000; // 60 seconds — matches TOKEN_TTL_SECONDS
|
|
23
|
+
export class TokenVerifier {
|
|
24
|
+
constructor(identity, jtiCache) {
|
|
25
|
+
this.identity = identity;
|
|
26
|
+
this.jtiCache = jtiCache;
|
|
27
|
+
}
|
|
28
|
+
async verify(token, capability) {
|
|
29
|
+
let unsafeClaims;
|
|
30
|
+
try {
|
|
31
|
+
const decoded = decodeJwtUnsafe(token);
|
|
32
|
+
unsafeClaims = decoded.payload;
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
throw new ChainAuthError("token_invalid", `JWT decode failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
36
|
+
}
|
|
37
|
+
if (unsafeClaims.sub !== this.identity.agentId) {
|
|
38
|
+
throw new ChainAuthError("agent_not_found", `JWT sub "${unsafeClaims.sub}" does not match registered agentId "${this.identity.agentId}"`);
|
|
39
|
+
}
|
|
40
|
+
if (unsafeClaims.iss !== this.identity.thumbprint) {
|
|
41
|
+
throw new ChainAuthError("token_invalid", "JWT iss does not match registered public key thumbprint — possible key substitution attack");
|
|
42
|
+
}
|
|
43
|
+
if (unsafeClaims.aud !== capability) {
|
|
44
|
+
throw new ChainAuthError("capability_denied", `JWT aud "${unsafeClaims.aud}" does not match requested capability "${capability}"`);
|
|
45
|
+
}
|
|
46
|
+
const publicKey = await this.identity.getPublicKey();
|
|
47
|
+
try {
|
|
48
|
+
await verifyJwtSignature(token, publicKey, { expectedTyp: "agent+jwt" });
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
throw new ChainAuthError("token_invalid", `Signature verification failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
52
|
+
}
|
|
53
|
+
this.assertTemporal(unsafeClaims);
|
|
54
|
+
this.jtiCache.assert(this.identity.agentId, unsafeClaims.jti);
|
|
55
|
+
if (!this.identity.hasCapability(capability)) {
|
|
56
|
+
throw new ChainAuthError("capability_denied", `Agent "${this.identity.agentId}" does not hold a grant for capability "${capability}"`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
agentId: this.identity.agentId,
|
|
60
|
+
agentName: this.identity.registration.agentName,
|
|
61
|
+
hostname: this.identity.registration.hostname,
|
|
62
|
+
capability,
|
|
63
|
+
jti: unsafeClaims.jti,
|
|
64
|
+
iat: unsafeClaims.iat,
|
|
65
|
+
exp: unsafeClaims.exp,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
assertTemporal(claims) {
|
|
69
|
+
if (typeof claims.iat !== "number" || typeof claims.exp !== "number") {
|
|
70
|
+
throw new ChainAuthError("token_invalid", "JWT missing iat or exp claims");
|
|
71
|
+
}
|
|
72
|
+
const nowMs = Date.now();
|
|
73
|
+
const iatMs = claims.iat * 1000;
|
|
74
|
+
const expMs = claims.exp * 1000;
|
|
75
|
+
if (iatMs > nowMs + CLOCK_SKEW_MS) {
|
|
76
|
+
throw new ChainAuthError("token_invalid", "JWT iat is in the future — clock skew too large or token pre-generated");
|
|
77
|
+
}
|
|
78
|
+
if (expMs < nowMs - CLOCK_SKEW_MS) {
|
|
79
|
+
throw new ChainAuthError("token_expired", "JWT has expired");
|
|
80
|
+
}
|
|
81
|
+
if (expMs - iatMs > JWT_MAX_AGE_MS + CLOCK_SKEW_MS) {
|
|
82
|
+
throw new ChainAuthError("token_invalid", `JWT lifetime of ${Math.round((expMs - iatMs) / 1000)}s exceeds maximum of ${JWT_MAX_AGE_MS / 1000}s`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=token-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-verifier.js","sourceRoot":"","sources":["../../src/auth/token-verifier.ts"],"names":[],"mappings":"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"}
|
package/dist/chain.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentsChain — the main entry point for the agents-chain package.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
*
|
|
6
|
+
* const chain = await AgentsChain.create({
|
|
7
|
+
* agentName: "summarizer",
|
|
8
|
+
* hostname: "my-app", // → agentId: "my-app-agent-<32hex>"
|
|
9
|
+
* capabilities: ["chat.completion", "embedding"],
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* const ai = chain.openai(new OpenAI({ apiKey }));
|
|
13
|
+
* const result = await ai.chat.completions.create({ model: "gpt-4o", ... });
|
|
14
|
+
*
|
|
15
|
+
* const log = chain.getAuditLog(); // All calls, decrypted
|
|
16
|
+
* const stats = chain.getStats(); // Summary counts
|
|
17
|
+
*/
|
|
18
|
+
import type { AgentConfig, ChainStats, AuditSnapshot } from "./types/chain.js";
|
|
19
|
+
import type { AuditEntry } from "./types/audit.js";
|
|
20
|
+
export declare class AgentsChain {
|
|
21
|
+
private readonly store;
|
|
22
|
+
private readonly identity;
|
|
23
|
+
private readonly builder;
|
|
24
|
+
private readonly verifier;
|
|
25
|
+
private readonly log;
|
|
26
|
+
private constructor();
|
|
27
|
+
static create(config: AgentConfig): Promise<AgentsChain>;
|
|
28
|
+
openai<T extends object>(client: T): T;
|
|
29
|
+
anthropic<T extends object>(client: T): T;
|
|
30
|
+
get agentId(): string;
|
|
31
|
+
get capabilities(): string[];
|
|
32
|
+
getAuditLog(): AuditEntry[];
|
|
33
|
+
exportAudit(): AuditSnapshot;
|
|
34
|
+
getStats(): ChainStats;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAW;IAE/B,OAAO;WAcM,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAa9D,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC;IAStC,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC;IASzC,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,YAAY,IAAI,MAAM,EAAE,CAE3B;IACD,WAAW,IAAI,UAAU,EAAE;IAG3B,WAAW,IAAI,aAAa;IAO5B,QAAQ,IAAI,UAAU;CAazB"}
|
package/dist/chain.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentsChain — the main entry point for the agents-chain package.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
*
|
|
6
|
+
* const chain = await AgentsChain.create({
|
|
7
|
+
* agentName: "summarizer",
|
|
8
|
+
* hostname: "my-app", // → agentId: "my-app-agent-<32hex>"
|
|
9
|
+
* capabilities: ["chat.completion", "embedding"],
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* const ai = chain.openai(new OpenAI({ apiKey }));
|
|
13
|
+
* const result = await ai.chat.completions.create({ model: "gpt-4o", ... });
|
|
14
|
+
*
|
|
15
|
+
* const log = chain.getAuditLog(); // All calls, decrypted
|
|
16
|
+
* const stats = chain.getStats(); // Summary counts
|
|
17
|
+
*/
|
|
18
|
+
import { EncryptedStore } from "./memory/encrypted-store.js";
|
|
19
|
+
import { JtiCache } from "./memory/jti-cache.js";
|
|
20
|
+
import { AgentIdentity } from "./identity/agent-identity.js";
|
|
21
|
+
import { TokenBuilder } from "./auth/token-builder.js";
|
|
22
|
+
import { TokenVerifier } from "./auth/token-verifier.js";
|
|
23
|
+
import { AuditLog } from "./audit/audit-log.js";
|
|
24
|
+
import { wrapOpenAI } from "./wrappers/openai-wrapper.js";
|
|
25
|
+
import { wrapAnthropic } from "./wrappers/anthropic-wrapper.js";
|
|
26
|
+
export class AgentsChain {
|
|
27
|
+
constructor(store, identity, builder, verifier, log) {
|
|
28
|
+
this.store = store;
|
|
29
|
+
this.identity = identity;
|
|
30
|
+
this.builder = builder;
|
|
31
|
+
this.verifier = verifier;
|
|
32
|
+
this.log = log;
|
|
33
|
+
}
|
|
34
|
+
static async create(config) {
|
|
35
|
+
const store = EncryptedStore.create(config.encryptionKey);
|
|
36
|
+
const jtiCache = new JtiCache();
|
|
37
|
+
const identity = await AgentIdentity.create(config, store);
|
|
38
|
+
const builder = new TokenBuilder(identity);
|
|
39
|
+
const verifier = new TokenVerifier(identity, jtiCache);
|
|
40
|
+
const log = new AuditLog(store);
|
|
41
|
+
return new AgentsChain(store, identity, builder, verifier, log);
|
|
42
|
+
}
|
|
43
|
+
// ─── SDK Wrappers ─────────────────────────────────────────────────────────
|
|
44
|
+
openai(client) {
|
|
45
|
+
return wrapOpenAI(client, {
|
|
46
|
+
identity: this.identity,
|
|
47
|
+
builder: this.builder,
|
|
48
|
+
verifier: this.verifier,
|
|
49
|
+
log: this.log,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
anthropic(client) {
|
|
53
|
+
return wrapAnthropic(client, {
|
|
54
|
+
identity: this.identity,
|
|
55
|
+
builder: this.builder,
|
|
56
|
+
verifier: this.verifier,
|
|
57
|
+
log: this.log,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
get agentId() {
|
|
61
|
+
return this.identity.agentId;
|
|
62
|
+
}
|
|
63
|
+
get capabilities() {
|
|
64
|
+
return this.identity.capabilityNames;
|
|
65
|
+
}
|
|
66
|
+
getAuditLog() {
|
|
67
|
+
return this.log.getAll();
|
|
68
|
+
}
|
|
69
|
+
exportAudit() {
|
|
70
|
+
return {
|
|
71
|
+
agentId: this.identity.agentId,
|
|
72
|
+
entries: this.log.getAll(),
|
|
73
|
+
exportedAt: Date.now(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
getStats() {
|
|
77
|
+
const entries = this.log.getAll();
|
|
78
|
+
return {
|
|
79
|
+
agentId: this.identity.agentId,
|
|
80
|
+
agentName: this.identity.registration.agentName,
|
|
81
|
+
hostname: this.identity.registration.hostname,
|
|
82
|
+
totalCalls: entries.length,
|
|
83
|
+
successfulCalls: entries.filter((e) => e.result === "success").length,
|
|
84
|
+
deniedCalls: entries.filter((e) => e.result === "denied").length,
|
|
85
|
+
errorCalls: entries.filter((e) => e.result === "error").length,
|
|
86
|
+
registeredAt: this.identity.registration.registeredAt,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
|