/** * McpCallerIdentity — ADR-377 Phase 3 (ruvnet/ruflo#2516, #2873). * * Per-invocation, Ed25519-signed capability tokens binding an MCP tool call * to a specific caller. Closes the gap identified in arXiv:2603.07473 * (Caller Identity Confusion in MCP): authorization state today persists * across callers with no re-verification, and `AgentAuthorizationPropagator` * (ADR-144)'s `checkToolCall` validates a *scope* but not that the caller * presenting it is who they claim to be for *this* call. * * Signing implementation follows the same pattern already used in this repo * for Ed25519 signing (`@claude-flow/browser`'s `witness-signer.ts`): native * `node:crypto`, zero new dependencies, sign+verify both supported (unlike * `@claude-flow/security`'s own `plugins/integrity-verifier.ts`, which uses * `@noble/ed25519` for verify-only). Reimplemented here rather than imported * from `@claude-flow/browser` because a security-primitives module * depending on the browser package would be a backwards layering * dependency; the pattern is ~15 lines and not worth a cross-package import * for that. * * Scope and honest limitations (per the ADR's own text) * -------------------------------------------------------- * This module implements token issuance/verification only. It does NOT * wire itself into any MCP tool dispatcher — this repo currently has at * least two distinct `ToolRegistry` implementations * (`v3/mcp/tool-registry.ts`, `v3/@claude-flow/mcp/src/tool-registry.ts`) * plus a third under `@claude-flow/shared`, and it was not safe to guess * which one is authoritative without risking silently wiring the wrong * dispatch path. `AgentAuthorizationPropagator.checkToolCall` (ADR-144) is * the natural composition point — call `verifyInvocationToken` first and * only proceed to `checkToolCall` if it passes — but that composition is * left to the caller rather than baked into `checkToolCall` itself, to * avoid changing ADR-144's already-shipped, already-tested behavior. * * Key distribution (how callers obtain a private key to sign with in the * first place) is explicitly out of scope — the ADR calls for "a follow-on * ADR for key distribution" before this ships enabled by default, which is * why `CLAUDE_FLOW_MCP_CALLER_AUTH` defaults to disabled. */ import type { KeyObject } from 'node:crypto'; export interface CallerIdentityKey { privateKey: KeyObject; publicKey: KeyObject; publicKeyHex: string; } export interface InvocationToken { /** Agent/principal id of the caller this token was issued to. */ callerId: string; /** Tool this token authorizes — a token issued for one tool cannot be * replayed against another. */ toolName: string; /** Unix ms the token was issued. */ issuedAt: number; /** Unix ms after which the token is no longer valid. */ expiresAt: number; /** Random per-token value; prevents replay of an otherwise-identical * token issued in the same millisecond. */ nonce: string; /** Hex-encoded Ed25519 signature over the canonicalized fields above. */ signature: string; } export interface TokenVerificationResult { valid: boolean; reason?: 'expired' | 'bad-signature' | 'tool-mismatch'; } /** Generate a fresh Ed25519 keypair. */ export declare function generateCallerIdentityKey(): CallerIdentityKey; /** Load a caller-identity key from a PEM-encoded private key string. */ export declare function loadCallerIdentityKey(privateKeyPem: string): CallerIdentityKey; /** * Issue a fresh, signed `InvocationToken` for `callerId` to call `toolName`. * Callers must present a *new* token per invocation — tokens are * single-tool-bound and short-lived (`ttlMs`, default 30s) by design; there * is no renewal API on purpose. */ export declare function issueInvocationToken(callerId: string, toolName: string, key: CallerIdentityKey, opts?: { ttlMs?: number; now?: number; }): InvocationToken; /** * Verify an `InvocationToken` against the issuing caller's public key and * (if provided) the tool the caller is about to invoke. Never throws. */ export declare function verifyInvocationToken(token: InvocationToken, publicKey: KeyObject, opts?: { toolName?: string; now?: number; }): TokenVerificationResult; /** Off by default — see the file header re: key distribution being out of scope pending a follow-on ADR. Only the literal `'true'` enables enforcement. */ export declare function isMcpCallerAuthEnabled(): boolean; //# sourceMappingURL=mcp-caller-identity.d.ts.map