W3C DID identity
Portable, cryptographic agent identity using W3C Decentralized Identifiers.
What are DIDs
W3C Decentralized Identifiers give agents a portable, cryptographic identity that works across services. Instead of an opaque token tied to one KavachOS instance, an agent gets a DID like did:key:z6Mk... backed by an Ed25519 keypair.
The agent can prove its identity to any service by signing a payload with its private key. The verifier resolves the DID to get the public key and checks the signature. No shared secrets, no central registry.
DIDs are optional. Regular kv_ bearer tokens work fine for single-service deployments. Use DIDs when agents need to prove identity across organizational boundaries.
Two DID methods
KavachOS supports two W3C DID methods:
| Method | Format | Best for |
|---|---|---|
did:key | did:key:z6Mk... | Self-contained identity. No server needed. Key is embedded in the identifier. |
did:web | did:web:auth.example.com:agents:agt_123 | Organization-backed identity. DID document hosted at a well-known URL. |
Generate a DID for an agent
const { agentDid, privateKeyJwk } = await kavach.did.generateKey(agent.id);
console.log(agentDid.did);
// did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK
// Store privateKeyJwk securely — it's shown once and never stored in the databaseConfigure your domain first:
const kavach = await createKavach({
database: { provider: 'sqlite', url: 'kavach.db' },
did: {
web: { domain: 'auth.example.com', path: 'agents' },
},
});
const { agentDid, privateKeyJwk } = await kavach.did.generateWeb(agent.id);
console.log(agentDid.did);
// did:web:auth.example.com:agents:agt_abc123Host the DID document at the resolved URL:
did:web:auth.example.com:agents:agt_abc123
→ https://auth.example.com/agents/agt_abc123/did.jsonThe private key is returned once and never stored in the database. Only the public key and DID document are persisted. Treat the private key like a bearer token.
Sign and verify payloads
An agent can sign a payload to prove it authored a request:
// Agent signs a payload
const signed = await kavach.did.sign(agent.id, {
action: 'deploy',
environment: 'staging',
timestamp: new Date().toISOString(),
}, privateKeyJwk);
console.log(signed.jws); // compact JWS string
console.log(signed.issuer); // did:key:z6Mk...A receiving service verifies the signature:
const result = await kavach.did.verify(signed.jws, agentDid.did);
if (result.valid) {
console.log(result.payload); // { action: 'deploy', ... }
console.log(result.issuer); // did:key:z6Mk...
}Verifiable presentations
A presentation is a signed JWT that bundles an agent's identity with its capabilities. Use this when an agent needs to prove both who it is and what it can do.
// Create a presentation
const jwt = await kavach.did.createPresentation({
agentId: agent.id,
did: agentDid.did,
privateKeyJwk,
capabilities: ['mcp:github:read', 'mcp:linear:write'],
audience: 'https://mcp.partner.com',
expiresIn: 300, // 5 minutes
});
// Verify on the receiving end
const result = await kavach.did.verifyPresentation(jwt);
if (result.valid) {
console.log(result.agentId); // agt_abc123
console.log(result.capabilities); // ['mcp:github:read', 'mcp:linear:write']
}DID document structure
Every agent DID resolves to a W3C DID document:
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:key:z6MkhaXg...",
"controller": "did:key:z6MkhaXg...",
"verificationMethod": [{
"id": "did:key:z6MkhaXg...#key-0",
"type": "JsonWebKey2020",
"controller": "did:key:z6MkhaXg...",
"publicKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "..."
}
}],
"authentication": ["did:key:z6MkhaXg...#key-0"],
"assertionMethod": ["did:key:z6MkhaXg...#key-0"],
"capabilityInvocation": ["did:key:z6MkhaXg...#key-0"],
"capabilityDelegation": ["did:key:z6MkhaXg...#key-0"]
}Retrieve a stored DID
const agentDid = await kavach.did.getAgentDid(agent.id);
if (agentDid) {
console.log(agentDid.did); // did:key:z6Mk...
console.log(agentDid.method); // 'key' or 'web'
}Resolve any DID
// Resolve did:key (local, no network)
const doc = await kavach.did.resolve('did:key:z6Mk...');
// Resolve did:web (fetches from HTTPS)
const doc = await kavach.did.resolve('did:web:auth.example.com');Prop
Type