multi-agent-protocol 0.0.3 → 0.0.6

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.
@@ -0,0 +1,748 @@
1
+ # MAP Authentication Specification
2
+
3
+ This specification defines how authentication is negotiated and performed in the Multi-Agent Protocol (MAP). The design prioritizes flexibility while providing interoperable defaults.
4
+
5
+ ## Design Principles
6
+
7
+ 1. **Pluggable mechanisms** - Support multiple auth methods with a standard negotiation flow
8
+ 2. **Sensible defaults** - Built-in support for common methods (bearer tokens, API keys)
9
+ 3. **Transport-aware** - Acknowledge that some auth happens at transport layer (mTLS)
10
+ 4. **Optional for local** - No auth overhead for trusted local connections (stdio)
11
+ 5. **Federation-ready** - Credentials can carry claims for cross-server authentication
12
+
13
+ ---
14
+
15
+ ## Authentication Methods
16
+
17
+ MAP defines the following standard authentication methods:
18
+
19
+ | Method | Description | Use Case |
20
+ |--------|-------------|----------|
21
+ | `none` | No authentication | Local subprocess agents, development |
22
+ | `bearer` | Bearer token (JWT or opaque) | OAuth2, IdP integration, M2M tokens |
23
+ | `api-key` | Simple API key | Simple integrations, internal services |
24
+ | `mtls` | Mutual TLS (transport layer) | High-security service-to-service |
25
+ | `did:wba` | DID-based, domain-anchored | Cross-org federation, open discovery |
26
+
27
+ ### Extension Methods
28
+
29
+ Custom authentication methods MUST use the `x-` prefix:
30
+
31
+ ```
32
+ x-custom-auth
33
+ x-kerberos
34
+ x-saml
35
+ ```
36
+
37
+ Servers MUST reject unknown methods that do not use the `x-` prefix.
38
+
39
+ ---
40
+
41
+ ## Wire Protocol
42
+
43
+ ### Server Authentication Capabilities
44
+
45
+ Servers advertise authentication requirements in the connect response:
46
+
47
+ ```typescript
48
+ interface ServerAuthCapabilities {
49
+ /** Supported authentication methods (in preference order) */
50
+ methods: AuthMethod[];
51
+
52
+ /** Is authentication required to proceed? */
53
+ required: boolean;
54
+
55
+ /** OAuth2 authorization server metadata URL (RFC 8414) */
56
+ oauth2MetadataUrl?: string;
57
+
58
+ /** JWKS URL for local JWT verification (RFC 7517) */
59
+ jwksUrl?: string;
60
+
61
+ /** Realm identifier for this server */
62
+ realm?: string;
63
+ }
64
+ ```
65
+
66
+ ### Client Authentication Credentials
67
+
68
+ Clients provide credentials using:
69
+
70
+ ```typescript
71
+ interface AuthCredentials {
72
+ /** The authentication method being used */
73
+ method: AuthMethod;
74
+
75
+ /** The credential value (token, API key, etc.) */
76
+ credential?: string;
77
+
78
+ /** Method-specific additional data */
79
+ metadata?: Record<string, unknown>;
80
+ }
81
+ ```
82
+
83
+ ### Authentication Result
84
+
85
+ Servers respond with:
86
+
87
+ ```typescript
88
+ interface AuthResult {
89
+ /** Whether authentication succeeded */
90
+ success: boolean;
91
+
92
+ /** Authenticated principal information */
93
+ principal?: {
94
+ /** Unique identifier for this principal */
95
+ id: string;
96
+
97
+ /** Token issuer (for federated auth) */
98
+ issuer?: string;
99
+
100
+ /** Additional claims from the credential */
101
+ claims?: Record<string, unknown>;
102
+ };
103
+
104
+ /** Error details if authentication failed */
105
+ error?: {
106
+ code: AuthErrorCode;
107
+ message: string;
108
+ };
109
+ }
110
+
111
+ type AuthErrorCode =
112
+ | 'invalid_credentials' // Credentials are malformed or invalid
113
+ | 'expired' // Credentials have expired
114
+ | 'insufficient_scope' // Valid credentials but insufficient permissions
115
+ | 'method_not_supported' // Requested method not supported by server
116
+ | 'auth_required'; // No credentials provided but auth is required
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Connection Flow
122
+
123
+ ### Flow 1: Auth Provided Upfront (Recommended)
124
+
125
+ When the client knows the server's auth requirements:
126
+
127
+ ```
128
+ Client Server
129
+ │ │
130
+ │──── map/connect ────────────────────────────►│
131
+ │ { participantType, auth: { method, credential } }
132
+ │ │
133
+ │◄─── connect response ───────────────────────│
134
+ │ { session, principal } │
135
+ │ │
136
+ ```
137
+
138
+ ```typescript
139
+ // Request
140
+ {
141
+ "jsonrpc": "2.0",
142
+ "id": 1,
143
+ "method": "map/connect",
144
+ "params": {
145
+ "protocolVersion": 1,
146
+ "participantType": "client",
147
+ "name": "my-client",
148
+ "auth": {
149
+ "method": "bearer",
150
+ "credential": "eyJhbGciOiJSUzI1NiIs..."
151
+ }
152
+ }
153
+ }
154
+
155
+ // Response (success)
156
+ {
157
+ "jsonrpc": "2.0",
158
+ "id": 1,
159
+ "result": {
160
+ "sessionId": "session_01ABC",
161
+ "participantId": "client_01XYZ",
162
+ "serverCapabilities": { ... },
163
+ "principal": {
164
+ "id": "user_123",
165
+ "issuer": "https://auth.example.com",
166
+ "claims": { "scope": "read write" }
167
+ }
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### Flow 2: Auth Negotiation
173
+
174
+ When the client doesn't know auth requirements:
175
+
176
+ ```
177
+ Client Server
178
+ │ │
179
+ │──── map/connect ────────────────────────────►│
180
+ │ { participantType } │
181
+ │ │
182
+ │◄─── auth_required response ─────────────────│
183
+ │ { authRequired: { methods, required } } │
184
+ │ │
185
+ │──── map/authenticate ───────────────────────►│
186
+ │ { method, credential } │
187
+ │ │
188
+ │◄─── auth result ────────────────────────────│
189
+ │ { success, session, principal } │
190
+ │ │
191
+ ```
192
+
193
+ ```typescript
194
+ // Initial connect (no auth)
195
+ {
196
+ "jsonrpc": "2.0",
197
+ "id": 1,
198
+ "method": "map/connect",
199
+ "params": {
200
+ "protocolVersion": 1,
201
+ "participantType": "client",
202
+ "name": "my-client"
203
+ }
204
+ }
205
+
206
+ // Server requires auth
207
+ {
208
+ "jsonrpc": "2.0",
209
+ "id": 1,
210
+ "result": {
211
+ "authRequired": {
212
+ "methods": ["bearer", "api-key"],
213
+ "required": true,
214
+ "realm": "map-server-prod",
215
+ "oauth2MetadataUrl": "https://auth.example.com/.well-known/oauth-authorization-server"
216
+ }
217
+ }
218
+ }
219
+
220
+ // Client authenticates
221
+ {
222
+ "jsonrpc": "2.0",
223
+ "id": 2,
224
+ "method": "map/authenticate",
225
+ "params": {
226
+ "method": "bearer",
227
+ "credential": "eyJhbGciOiJSUzI1NiIs..."
228
+ }
229
+ }
230
+
231
+ // Server confirms
232
+ {
233
+ "jsonrpc": "2.0",
234
+ "id": 2,
235
+ "result": {
236
+ "success": true,
237
+ "sessionId": "session_01ABC",
238
+ "participantId": "client_01XYZ",
239
+ "principal": {
240
+ "id": "user_123",
241
+ "claims": { "scope": "read write" }
242
+ }
243
+ }
244
+ }
245
+ ```
246
+
247
+ ### Flow 3: No Auth Required
248
+
249
+ For local connections or development:
250
+
251
+ ```typescript
252
+ // Request
253
+ {
254
+ "jsonrpc": "2.0",
255
+ "id": 1,
256
+ "method": "map/connect",
257
+ "params": {
258
+ "protocolVersion": 1,
259
+ "participantType": "agent",
260
+ "name": "local-worker",
261
+ "auth": { "method": "none" }
262
+ }
263
+ }
264
+
265
+ // Response
266
+ {
267
+ "jsonrpc": "2.0",
268
+ "id": 1,
269
+ "result": {
270
+ "sessionId": "session_01ABC",
271
+ "participantId": "agent_01XYZ",
272
+ "principal": {
273
+ "id": "anonymous"
274
+ }
275
+ }
276
+ }
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Method-Specific Details
282
+
283
+ ### Bearer Tokens (`bearer`)
284
+
285
+ Bearer tokens are opaque strings or JWTs. The server is responsible for validation.
286
+
287
+ **Credential format:** The raw token string
288
+
289
+ ```typescript
290
+ {
291
+ "method": "bearer",
292
+ "credential": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
293
+ }
294
+ ```
295
+
296
+ **JWT Claims (when using JWT):**
297
+
298
+ | Claim | Description | Required |
299
+ |-------|-------------|----------|
300
+ | `sub` | Subject (principal ID) | Yes |
301
+ | `iss` | Issuer | Recommended |
302
+ | `aud` | Audience (server identifier) | Recommended |
303
+ | `exp` | Expiration time | Recommended |
304
+ | `iat` | Issued at | Recommended |
305
+ | `scope` | Space-separated permission scopes | Optional |
306
+ | `map:capabilities` | MAP-specific capabilities | Optional |
307
+
308
+ **Example JWT payload:**
309
+
310
+ ```json
311
+ {
312
+ "sub": "agent_worker_01",
313
+ "iss": "https://auth.example.com",
314
+ "aud": "map-server-prod",
315
+ "exp": 1706227200,
316
+ "iat": 1706223600,
317
+ "scope": "map:read map:write map:agent",
318
+ "map:capabilities": {
319
+ "canSpawn": true,
320
+ "canSend": true
321
+ }
322
+ }
323
+ ```
324
+
325
+ ### API Keys (`api-key`)
326
+
327
+ Simple static keys for straightforward integrations.
328
+
329
+ **Credential format:** The API key string
330
+
331
+ ```typescript
332
+ {
333
+ "method": "api-key",
334
+ "credential": "map_sk_live_abc123def456..."
335
+ }
336
+ ```
337
+
338
+ **Security considerations:**
339
+ - MUST only be used over TLS
340
+ - Keys SHOULD be rotatable without service interruption
341
+ - Keys SHOULD have associated metadata (owner, scopes, expiry)
342
+
343
+ ### Mutual TLS (`mtls`)
344
+
345
+ Authentication is performed at the transport layer via client certificates.
346
+
347
+ **Credential format:** No credential in the protocol; certificate is validated at transport.
348
+
349
+ ```typescript
350
+ {
351
+ "method": "mtls"
352
+ // No credential needed - cert already validated
353
+ }
354
+ ```
355
+
356
+ **Metadata:** The server MAY extract principal information from the certificate:
357
+
358
+ ```typescript
359
+ {
360
+ "method": "mtls",
361
+ "metadata": {
362
+ "cn": "agent-worker-01.example.com",
363
+ "fingerprint": "sha256:abc123..."
364
+ }
365
+ }
366
+ ```
367
+
368
+ ### No Authentication (`none`)
369
+
370
+ For trusted local connections.
371
+
372
+ ```typescript
373
+ {
374
+ "method": "none"
375
+ }
376
+ ```
377
+
378
+ **When to use:**
379
+ - Subprocess agents connected via stdio
380
+ - In-process connections
381
+ - Development/testing environments
382
+ - Behind a trusted proxy that handles auth
383
+
384
+ **Servers MAY:**
385
+ - Reject `none` based on transport type (e.g., require auth for WebSocket)
386
+ - Assign a default principal for anonymous connections
387
+
388
+ ### DID:WBA (`did:wba`)
389
+
390
+ Domain-anchored decentralized identity based on the W3C `did:wba` method. Identity is derived from domain ownership: a DID like `did:wba:agents.example.com:gateway` resolves to a DID document hosted at `https://agents.example.com/gateway/did.json`.
391
+
392
+ **Credential format:** DID and cryptographic proof in metadata
393
+
394
+ ```typescript
395
+ {
396
+ "method": "did:wba",
397
+ "metadata": {
398
+ "did": "did:wba:agents.example.com:gateway",
399
+ "proof": {
400
+ "type": "JsonWebSignature2020",
401
+ "created": "2026-02-10T12:00:00.000Z",
402
+ "challenge": "map_chal_01ABCDEFGHJ0123456789AB",
403
+ "jws": "base64url-encoded-ecdsa-signature"
404
+ }
405
+ }
406
+ }
407
+ ```
408
+
409
+ **DID Document:** The resolved DID document MUST contain:
410
+ - `verificationMethod` with the public key used to verify the proof
411
+ - `authentication` referencing the verification method
412
+ - Optionally, a `service` entry of type `MAPFederationEndpoint` with the MAP WebSocket URL
413
+
414
+ **Proof verification:**
415
+ 1. Server generates a challenge nonce (format: `map_chal_<ULID>`)
416
+ 2. Client signs `challenge.did.created` using ECDSA P-256 with its private key
417
+ 3. Server resolves DID → fetches DID document → extracts public key
418
+ 4. Server verifies the JWS signature against the public key and checks proof freshness
419
+
420
+ **Security considerations:**
421
+ - DID documents are fetched over HTTPS — domain ownership proves identity
422
+ - Proof freshness is enforced via the `created` timestamp (default max age: 5 minutes)
423
+ - Servers MAY maintain a trusted domains list to restrict accepted DIDs
424
+ - DID document caching with configurable TTL prevents excessive lookups
425
+
426
+ **When to use:**
427
+ - Cross-organization federation where pre-shared credentials are impractical
428
+ - Open discovery scenarios where peers find each other via DID documents
429
+ - Systems that need globally unique, verifiable agent identities
430
+
431
+ **SDK support:**
432
+ - `DIDWBAAuthenticator` — server-side authenticator (see `ts-sdk/src/server/auth/did-wba-authenticator.ts`)
433
+ - `generateDIDWBAProof()` / `verifyDIDWBAProof()` — proof utilities (see `ts-sdk/src/federation/did-wba/proof.ts`)
434
+ - `DIDWBAResolver` — DID document resolution with caching (see `ts-sdk/src/federation/did-wba/resolver.ts`)
435
+
436
+ ---
437
+
438
+ ## Token Refresh
439
+
440
+ For long-lived connections with expiring tokens:
441
+
442
+ ### Proactive Refresh
443
+
444
+ Client refreshes before expiration:
445
+
446
+ ```typescript
447
+ // Request
448
+ {
449
+ "jsonrpc": "2.0",
450
+ "id": 10,
451
+ "method": "map/auth/refresh",
452
+ "params": {
453
+ "credential": "eyJhbGciOiJSUzI1NiIs..." // New token
454
+ }
455
+ }
456
+
457
+ // Response
458
+ {
459
+ "jsonrpc": "2.0",
460
+ "id": 10,
461
+ "result": {
462
+ "success": true,
463
+ "principal": {
464
+ "id": "user_123",
465
+ "claims": { "exp": 1706230800 }
466
+ }
467
+ }
468
+ }
469
+ ```
470
+
471
+ ### Server-Initiated Expiration Warning
472
+
473
+ Server notifies client before token expires:
474
+
475
+ ```typescript
476
+ // Notification (server → client)
477
+ {
478
+ "jsonrpc": "2.0",
479
+ "method": "map/auth/expiring",
480
+ "params": {
481
+ "expiresAt": 1706227200,
482
+ "refreshBefore": 1706226900 // Suggested refresh time
483
+ }
484
+ }
485
+ ```
486
+
487
+ ### Forced Re-authentication
488
+
489
+ If token expires or is revoked:
490
+
491
+ ```typescript
492
+ // Notification (server → client)
493
+ {
494
+ "jsonrpc": "2.0",
495
+ "method": "map/auth/revoked",
496
+ "params": {
497
+ "reason": "token_expired",
498
+ "message": "Your session has expired. Please re-authenticate.",
499
+ "gracePeriodMs": 5000 // Time before disconnect
500
+ }
501
+ }
502
+ ```
503
+
504
+ ---
505
+
506
+ ## Federation Authentication
507
+
508
+ For cross-server authentication in federated deployments:
509
+
510
+ ### Token Requirements
511
+
512
+ Federated tokens MUST include:
513
+
514
+ | Claim | Description |
515
+ |-------|-------------|
516
+ | `iss` | Issuing server's identifier |
517
+ | `aud` | Target server(s) - array or string |
518
+ | `sub` | Original principal identifier |
519
+ | `map:federation` | Federation-specific claims |
520
+
521
+ **Example federated token:**
522
+
523
+ ```json
524
+ {
525
+ "sub": "agent_worker_01",
526
+ "iss": "https://server-a.example.com",
527
+ "aud": ["https://server-b.example.com", "https://server-c.example.com"],
528
+ "exp": 1706227200,
529
+ "map:federation": {
530
+ "originServer": "server-a",
531
+ "delegatedCapabilities": {
532
+ "canSend": true,
533
+ "canQuery": true
534
+ },
535
+ "hopCount": 1,
536
+ "maxHops": 3
537
+ }
538
+ }
539
+ ```
540
+
541
+ ### Trust Establishment
542
+
543
+ Federated servers MUST:
544
+ 1. Maintain an allowlist of trusted issuers
545
+ 2. Verify token signatures against issuer's JWKS
546
+ 3. Validate audience claims include their own identifier
547
+ 4. Enforce hop count limits to prevent routing loops
548
+
549
+ ---
550
+
551
+ ## Error Handling
552
+
553
+ ### Authentication Errors
554
+
555
+ | Error Code | HTTP Equivalent | Description |
556
+ |------------|-----------------|-------------|
557
+ | `AUTH_REQUIRED` | 401 | Authentication required but not provided |
558
+ | `INVALID_CREDENTIALS` | 401 | Credentials invalid or malformed |
559
+ | `EXPIRED` | 401 | Credentials have expired |
560
+ | `INSUFFICIENT_SCOPE` | 403 | Valid credentials but lacks required permissions |
561
+ | `METHOD_NOT_SUPPORTED` | 400 | Requested auth method not supported |
562
+
563
+ **Error response format:**
564
+
565
+ ```typescript
566
+ {
567
+ "jsonrpc": "2.0",
568
+ "id": 1,
569
+ "error": {
570
+ "code": -32001, // MAP error code
571
+ "message": "Authentication failed",
572
+ "data": {
573
+ "authError": {
574
+ "code": "invalid_credentials",
575
+ "message": "JWT signature verification failed"
576
+ },
577
+ "authRequired": {
578
+ "methods": ["bearer", "api-key"],
579
+ "required": true
580
+ }
581
+ }
582
+ }
583
+ }
584
+ ```
585
+
586
+ ---
587
+
588
+ ## Security Considerations
589
+
590
+ ### Transport Security
591
+
592
+ 1. **TLS Required** - All remote connections MUST use TLS 1.2+
593
+ 2. **Certificate Validation** - Clients MUST validate server certificates
594
+ 3. **No Downgrade** - Servers SHOULD reject non-TLS connections for auth methods other than `none`
595
+
596
+ ### Token Security
597
+
598
+ 1. **Short Lifetimes** - Bearer tokens SHOULD have lifetimes ≤ 1 hour for M2M
599
+ 2. **Audience Validation** - Servers MUST validate `aud` claims
600
+ 3. **Signature Algorithms** - Prefer RS256/ES256; avoid HS256 for distributed systems
601
+ 4. **Key Rotation** - Servers SHOULD support JWKS key rotation
602
+
603
+ ### API Key Security
604
+
605
+ 1. **Entropy** - Keys MUST have ≥ 256 bits of entropy
606
+ 2. **Prefix** - Keys SHOULD use identifiable prefixes (e.g., `map_sk_`)
607
+ 3. **Hashing** - Servers MUST store only hashed keys
608
+ 4. **Rotation** - Support key rotation without service interruption
609
+
610
+ ### Logging and Audit
611
+
612
+ 1. **No Credential Logging** - Credentials MUST NOT appear in logs
613
+ 2. **Auth Events** - Log authentication attempts (success/failure) with principal ID
614
+ 3. **Rate Limiting** - Implement rate limiting on auth endpoints
615
+
616
+ ---
617
+
618
+ ## Implementation Requirements
619
+
620
+ ### Servers MUST
621
+
622
+ 1. Support at least one of: `bearer`, `api-key`, or `none`
623
+ 2. Advertise supported methods in auth capabilities
624
+ 3. Return proper error codes for auth failures
625
+ 4. Validate credentials before establishing session
626
+
627
+ ### Servers SHOULD
628
+
629
+ 1. Support `bearer` tokens with JWT validation
630
+ 2. Provide JWKS endpoint or reference external JWKS
631
+ 3. Support token refresh for long-lived connections
632
+ 4. Implement rate limiting on authentication
633
+
634
+ ### Clients MUST
635
+
636
+ 1. Support providing credentials via `auth` parameter
637
+ 2. Handle `authRequired` response and provide credentials
638
+ 3. Handle auth errors gracefully
639
+
640
+ ### Clients SHOULD
641
+
642
+ 1. Implement automatic token refresh before expiration
643
+ 2. Support credential caching with proper security
644
+ 3. Handle `map/auth/expiring` notifications
645
+
646
+ ---
647
+
648
+ ## Examples
649
+
650
+ ### Example 1: Production Server with JWT
651
+
652
+ ```typescript
653
+ const server = new MAPServer({
654
+ auth: {
655
+ required: true,
656
+ methods: ['bearer'],
657
+ authenticators: [
658
+ new JWTAuthenticator({
659
+ jwksUrl: 'https://auth.example.com/.well-known/jwks.json',
660
+ issuer: 'https://auth.example.com',
661
+ audience: 'map-server-prod'
662
+ })
663
+ ]
664
+ }
665
+ });
666
+ ```
667
+
668
+ ### Example 2: Internal Service with API Keys
669
+
670
+ ```typescript
671
+ const server = new MAPServer({
672
+ auth: {
673
+ required: true,
674
+ methods: ['api-key'],
675
+ authenticators: [
676
+ new APIKeyAuthenticator({
677
+ validateKey: async (key) => {
678
+ const record = await db.apiKeys.findByHash(hash(key));
679
+ return {
680
+ valid: !!record && !record.revoked,
681
+ principalId: record?.ownerId,
682
+ metadata: { scopes: record?.scopes }
683
+ };
684
+ }
685
+ })
686
+ ]
687
+ }
688
+ });
689
+ ```
690
+
691
+ ### Example 3: Development Server
692
+
693
+ ```typescript
694
+ const server = new MAPServer({
695
+ auth: {
696
+ required: false,
697
+ methods: ['none', 'bearer'],
698
+ authenticators: [
699
+ new NoAuthAuthenticator(),
700
+ new JWTAuthenticator({ /* ... */ }) // Optional for testing
701
+ ]
702
+ }
703
+ });
704
+ ```
705
+
706
+ ### Example 4: Hybrid Production
707
+
708
+ ```typescript
709
+ const server = new MAPServer({
710
+ auth: {
711
+ required: true,
712
+ methods: ['bearer', 'api-key', 'mtls'],
713
+ authenticators: [
714
+ new JWTAuthenticator({ /* ... */ }),
715
+ new APIKeyAuthenticator({ /* ... */ }),
716
+ new MTLSAuthenticator({ /* ... */ })
717
+ ]
718
+ }
719
+ });
720
+ ```
721
+
722
+ ### Example 5: Federation Server with DID:WBA
723
+
724
+ ```typescript
725
+ import { DIDWBAAuthenticator } from '@anthropic/multi-agent-protocol/server/auth';
726
+
727
+ const server = new MAPServer({
728
+ auth: {
729
+ required: true,
730
+ methods: ['did:wba', 'bearer'],
731
+ authenticators: [
732
+ new DIDWBAAuthenticator({
733
+ trustedDomains: ['*.example.com', 'partner.org'],
734
+ }),
735
+ new JWTAuthenticator({ /* ... */ })
736
+ ]
737
+ }
738
+ });
739
+ ```
740
+
741
+ ---
742
+
743
+ ## Open Questions
744
+
745
+ 1. **Scope standardization** - Should MAP define standard scope strings (e.g., `map:read`, `map:agent:spawn`)?
746
+ 2. **Principal-to-permissions mapping** - Should the protocol define how claims map to capabilities?
747
+ 3. **Multi-factor** - Is there a use case for multi-factor auth in agent connections?
748
+ 4. **Session binding** - Should tokens be bound to specific sessions to prevent replay?