Identity API
The Identity module provides decentralized identifier (DID) resolution, agent manifest fetching, and cryptographic signing/verification for secure agent-to-agent authentication.
DID Method Support
| Method | Description | Resolution |
|---|---|---|
did:web |
Domain-based DIDs | Fetches /.well-known/did.json via HTTPS |
did:key |
Self-contained key-based DIDs | Constructs DID Document from embedded key |
Classes
DIDResolver
Resolves DID documents for supported DID methods.
import { DIDResolver } from '@a2aletheia/sdk';
const resolver = new DIDResolver();
Methods
resolve(did: DID): Promise<DIDDocument>
Resolves any supported DID method. Automatically routes to the appropriate resolver based on the DID method prefix.
Parameters:
did- A valid DID string (e.g.,did:web:example.comordid:key:z6Mk...)
Returns: Promise resolving to a DID Document
Throws: Error if DID method is unsupported
const didDoc = await resolver.resolve('did:web:agent.example.com');
const didDoc = await resolver.resolve('did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGcpnnJtaUxeJq');
resolveWeb(did: DID): Promise<DIDDocument>
Resolves a did:web DID by fetching the DID document from the well-known location.
Resolution Logic:
did:web:example.com→https://example.com/.well-known/did.jsondid:web:example.com:path:to:agent→https://example.com/path/to/agent/did.json
Parameters:
did- A validdid:webDID string
Returns: Promise resolving to a DID Document
Throws: Error if DID is invalid or HTTP request fails
const didDoc = await resolver.resolveWeb('did:web:agent.example.com');
console.log(didDoc.id); // did:web:agent.example.com
resolveKey(did: DID): Promise<DIDDocument>
Resolves a did:key DID by constructing a DID Document from the embedded key material.
Parameters:
did- A validdid:keyDID string
Returns: Promise resolving to a constructed DID Document
Supports: Ed25519 and secp256k1 multicodec keys
const didDoc = await resolver.resolveKey('did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGcpnnJtaUxeJq');
console.log(didDoc.verificationMethod?.[0]?.publicKeyMultibase);
ManifestFetcher
Fetches and validates A2A-compliant agent manifests from .well-known endpoints or explicit URLs.
import { ManifestFetcher } from '@a2aletheia/sdk';
const fetcher = new ManifestFetcher();
Methods
fetch(baseUrl: string): Promise<AgentManifest>
Fetches an agent manifest from the standard .well-known/agent-card.json location.
Parameters:
baseUrl- The base URL of the agent (e.g.,https://agent.example.com)
Returns: Promise resolving to a validated AgentManifest
Throws: Error if fetch fails or manifest validation fails
const manifest = await fetcher.fetch('https://agent.example.com');
console.log(manifest.name, manifest.skills);
fetchFromUrl(manifestUrl: string): Promise<AgentManifest>
Fetches an agent manifest from an explicit URL (not necessarily .well-known).
Parameters:
manifestUrl- The full URL to the manifest JSON file
Returns: Promise resolving to a validated AgentManifest
Throws: Error if fetch fails or manifest validation fails
const manifest = await fetcher.fetchFromUrl('https://cdn.example.com/agents/my-agent-card.json');
Functions
generateAgentKeyPair
Generates a new Ed25519 key pair suitable for agent identity and message signing.
function generateAgentKeyPair(): Promise<AgentKeyPair>
Returns: Promise resolving to an AgentKeyPair object
import { generateAgentKeyPair } from '@a2aletheia/sdk';
const keys = await generateAgentKeyPair();
console.log(keys.didKey); // did:key:z6Mk...
console.log(keys.publicKeyMultibase); // z6Mk...
⚠️ Security Warning: Store
keys.privateKeysecurely and never expose it in logs, client-side code, or version control. The private key is the cryptographic proof of agent identity.
signAgentMessage
Signs a message with an agent’s private key, creating a verifiable signed message.
function signAgentMessage<T>(
message: T,
privateKey: string,
signerDid: string
): Promise<SignedMessage<T>>
Parameters:
message- The payload to sign (will be JSON stringified)privateKey- Agent’s private key as hex stringsignerDid- The DID of the signing agent
Returns: Promise resolving to a SignedMessage<T>
import { signAgentMessage } from '@a2aletheia/sdk';
const signed = await signAgentMessage(
{ action: 'book', hotelId: '123', dates: ['2024-03-15'] },
keys.privateKey,
keys.didKey
);
// signed = {
// payload: { action: 'book', ... },
// signature: 'a1b2c3...',
// signer: 'did:key:z6Mk...',
// timestamp: 1708051200000
// }
verifyAgentSignature
Verifies a signed message using the signer’s known public key.
function verifyAgentSignature<T>(
signedMessage: SignedMessage<T>,
publicKey: string
): Promise<boolean>
Parameters:
signedMessage- The signed message to verifypublicKey- Signer’s public key as hex string
Returns: Promise resolving to true if signature is valid, false otherwise
import { verifyAgentSignature } from '@a2aletheia/sdk';
const isValid = await verifyAgentSignature(signed, keys.publicKey);
if (!isValid) {
throw new Error('Signature verification failed');
}
verifyAgentMessageWithDID
Verifies a signed message by resolving the signer’s DID document. This is the primary method for agent-to-agent authentication.
function verifyAgentMessageWithDID<T>(
signedMessage: SignedMessage<T>,
didDocument: DIDDocument
): Promise<boolean>
Parameters:
signedMessage- The signed message to verifydidDocument- The signer’s resolved DID document
Returns: Promise resolving to true if signature is valid and matches the DID document
Verification Process:
- Validates DID document ID matches the signer
- Extracts public key from verification methods
- Verifies signature against the extracted key
import { DIDResolver, verifyAgentMessageWithDID } from '@a2aletheia/sdk';
const resolver = new DIDResolver();
const didDoc = await resolver.resolve(signedMessage.signer);
const isValid = await verifyAgentMessageWithDID(signedMessage, didDoc);
if (!isValid) {
throw new Error('Message signature invalid - not from claimed agent!');
}
Types
AgentKeyPair
interface AgentKeyPair {
/** Private key (hex string) - KEEP SECRET! */
privateKey: string;
/** Public key (hex string) */
publicKey: string;
/** Public key in multibase format (for DID documents) */
publicKeyMultibase: string;
/** Generated did:key identifier */
didKey: string;
}
SignedMessage<T>
interface SignedMessage<T = unknown> {
/** The original message payload */
payload: T;
/** Ed25519 signature (hex string) */
signature: string;
/** DID of the signer */
signer: string;
/** Timestamp when signed (Unix ms) */
timestamp: number;
}
DID
type DID = string; // Must match pattern: ^did:(web|key|ethr|pkh):.+$
DIDDocument
interface DIDDocument {
'@context': string[];
id: string;
controller?: string;
verificationMethod?: VerificationMethod[];
authentication?: string[];
assertionMethod?: string[];
service?: DIDService[];
}
VerificationMethod
interface VerificationMethod {
id: string;
type: string;
controller: string;
publicKeyMultibase?: string;
publicKeyJwk?: Record<string, unknown>;
}
DIDService
interface DIDService {
id: string;
type: string;
serviceEndpoint: string; // URL
}
Examples
Key Generation and Secure Storage
import { generateAgentKeyPair } from '@a2aletheia/sdk';
// Generate identity keys
const keys = await generateAgentKeyPair();
console.log('Agent DID:', keys.didKey);
console.log('Public Key (multibase):', keys.publicKeyMultibase);
// CRITICAL: Store privateKey securely (env vars, secrets manager, etc.)
// NEVER commit to version control or expose in client-side code
await storeSecurely('AGENT_PRIVATE_KEY', keys.privateKey);
DID Resolution
import { DIDResolver } from '@a2aletheia/sdk';
const resolver = new DIDResolver();
// Resolve did:web (fetches from HTTPS endpoint)
const webDidDoc = await resolver.resolve('did:web:api.example.com');
console.log('Authentication methods:', webDidDoc.authentication);
// Resolve did:key (constructs from key material)
const keyDidDoc = await resolver.resolve('did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGcpnnJtaUxeJq');
console.log('Public key:', keyDidDoc.verificationMethod?.[0]?.publicKeyMultibase);
Message Signing and Verification
import { generateAgentKeyPair, signAgentMessage, verifyAgentSignature } from '@a2aletheia/sdk';
// Sender side: Sign a message
const keys = await generateAgentKeyPair();
const signed = await signAgentMessage(
{ type: 'task_request', taskId: 'abc-123', action: 'execute' },
keys.privateKey,
keys.didKey
);
// Receiver side: Verify with known public key
const isValid = await verifyAgentSignature(signed, keys.publicKey);
console.log('Signature valid:', isValid);
End-to-End Agent Authentication Flow
import {
DIDResolver,
ManifestFetcher,
signAgentMessage,
verifyAgentMessageWithDID,
} from '@a2aletheia/sdk';
// === Agent A: Send authenticated request ===
const agentAKeys = await generateAgentKeyPair();
const request = {
type: 'capability_invoke',
capability: 'hotel-booking',
params: { hotelId: 'h-001', dates: ['2024-06-01', '2024-06-03'] }
};
const signedRequest = await signAgentMessage(
request,
agentAKeys.privateKey,
agentAKeys.didKey
);
// === Agent B: Verify and process ===
const resolver = new DIDResolver();
// 1. Resolve sender's DID
const senderDidDoc = await resolver.resolve(signedRequest.signer);
// 2. Verify signature
const isValid = await verifyAgentMessageWithDID(signedRequest, senderDidDoc);
if (!isValid) {
throw new Error('Authentication failed: invalid signature');
}
// 3. Request authenticated - process the capability
console.log('Authenticated request from:', signedRequest.signer);
console.log('Payload:', signedRequest.payload);
Fetching Agent Manifests
import { ManifestFetcher } from '@a2aletheia/sdk';
const fetcher = new ManifestFetcher();
// From standard .well-known location
const manifest = await fetcher.fetch('https://booking-agent.example.com');
console.log('Agent:', manifest.name);
console.log('Version:', manifest.version);
console.log('Skills:', manifest.skills.map(s => s.name));
// Check for DID in Aletheia extensions
if (manifest.aletheiaExtensions?.did) {
console.log('Agent DID:', manifest.aletheiaExtensions.did);
}
Related APIs
- Client API - High-level client with integrated DID resolution
- Types API - Full type definitions and Zod schemas