pragma.vision Your technology observatory

The press · AI Trust & Identity · filed 2026-05-13 · updated 2026-07-10

W3C DIDs for AI Agents: Implementing did:tp: From Scratch

A working did:tp: implementation. Four namespaces, dual-key (Ed25519 + ML-DSA-65), resolution pipeline, verifiable credentials, edge-deployed.

#did #w3c-did #did-tp #decentralized-identity #ed25519 #ml-dsa-65 #verifiable-credentials #cloudflare-workers

The problem

Every human on the internet has a way to prove who they are. Passwords, passports, biometric scans, government-issued IDs — the infrastructure for human identity verification has been developed over decades. AI agents have none of it. A language model that books your flights, a code review bot that pushes to your repositories, an invoice processor that moves your money — none of them carry verifiable identity. They operate on borrowed credentials, shared API keys, and implicit trust. Non-human identities now outnumber humans 144 to 1 and growing 44% year over year. Seven of the ten OWASP NHI risks trace back to the same root cause: agents that cannot cryptographically prove who they are.

The W3C Decentralized Identifiers specification answered this in 2022. DID Core 1.0 (W3C Recommendation, July 2022) defines globally unique, cryptographically verifiable identifiers that do not depend on any centralized registry. The specification is method-agnostic — anyone can define a new DID method tailored to a specific domain. did:tp: is the method built for AI agents: four namespaces (agent, operator, service, device), mandatory hybrid signatures (Ed25519 classical + ML-DSA-65 post-quantum), resolvable through a Cloudflare Workers edge pipeline in sub-50ms.

This walks through the implementation: the DID Document structure, the four namespace semantics, the dual-key generation, the resolution pipeline with KV caching, and the verifiable-credential layer that issues TrustBadge credentials anchored to did:tp: agents.

Free sample

See the structure and voice before you buy.

Download the sample (PDF)

What most people get wrong

Mistake one: treating a DID like a UUID. A DID is a URI with a structure: did:method-name:method-specific-id. The method-name (tp, web, key, ion) determines how the DID is created, resolved, updated, and deactivated. The method-specific-id carries semantic structure — for did:tp:, four namespaces (agent, operator, service, device) each with distinct semantics. An agent DID (did:tp:agent:acme-corp:invoice-processor) cannot be used where an operator DID is required. A service DID cannot issue verifiable credentials. The namespace controls capability. Mixing them creates security holes — and the resolver must validate.

Mistake two: shipping single-signature credentials. Ed25519 signatures are universally compatible, well-tested, fast, and they are not quantum-safe. NIST published FIPS 204 (ML-DSA-65) in 2024 as the post-quantum digital signature standard. The window for “harvest now, decrypt later” attacks against long-lived agent credentials is open today. The hybrid model — every DID Document carries both an Ed25519 verification method and an ML-DSA-65 verification method, and every signature is verified against both — is the only signature shape that survives the next decade. The did:tp: method mandates it. Partial rotation (rotating the classical key without the post-quantum key, or vice versa) leaves the DID in an insecure state and the resolver rejects it.

This article is the short version — W3C DIDs for AI Agents: Implementing did:tp: from Scratch is the full playbook.

Get the ebook — $29

A working approach

The did:tp: method has four moving parts: namespaces, document structure, dual-key generation, and resolution pipeline.

1. Four namespaces with distinct semantics:

NamespaceSubjectKey signatureDelegationExample
agentAutonomous AI agentsHybrid requiredReceives from operatordid:tp:agent:acme-corp:invoice-processor
operatorOrganizations (KYB-verified)Hybrid requiredGrants to agentsdid:tp:operator:acme-corp:root
serviceAPIs, MCP servers, webhooksHybrid requiredControlled by operatordid:tp:service:pragma:mcp-server
deviceIoT, HSMs, edge nodesHybrid optionalHardware-bounddid:tp:device:logistics:drone-42

Agent DIDs carry a dynamic trust score. Operator DIDs carry capability delegation. Service DIDs include an apiSpecification link (typically OpenAPI). Device DIDs are authentication-only (not assertion).

2. DID Document structure with mandatory hybrid keys:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1",
    "https://trustauthority.ai/did/v1"
  ],
  "id": "did:tp:agent:acme-corp:invoice-processor",
  "verificationMethod": [
    {
      "id": "did:tp:agent:acme-corp:invoice-processor#key-1",
      "type": "Ed25519VerificationKey2020",
      "controller": "did:tp:agent:acme-corp:invoice-processor",
      "publicKeyMultibase": "z6Mkf5rGMoatrSj1f..."
    },
    {
      "id": "did:tp:agent:acme-corp:invoice-processor#key-pq",
      "type": "MLDSA65VerificationKey2024",
      "controller": "did:tp:agent:acme-corp:invoice-processor",
      "publicKeyMultibase": "zUC7LbYk..."
    }
  ],
  "authentication": ["did:tp:agent:acme-corp:invoice-processor#key-1"],
  "assertionMethod": [
    "did:tp:agent:acme-corp:invoice-processor#key-1",
    "did:tp:agent:acme-corp:invoice-processor#key-pq"
  ],
  "service": [
    {
      "id": "did:tp:agent:acme-corp:invoice-processor#endpoint",
      "type": "AgentEndpoint",
      "serviceEndpoint": "https://agents.acme.com/invoice-processor"
    },
    {
      "id": "did:tp:agent:acme-corp:invoice-processor#trust",
      "type": "TrustAuthorityService",
      "serviceEndpoint": "https://trustauthority.ai/api/v1/trust/did:tp:agent:..."
    }
  ]
}

3. Key generation runs two algorithms from one entropy source:

import { ed25519 } from '@noble/curves/ed25519';
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa';

async function generateDidKeys(): Promise<DidKeyPair> {
  const seed = crypto.getRandomValues(new Uint8Array(32));

  // Classical: Ed25519 (32-byte keys, 64-byte signatures)
  const classicalSk = seed;
  const classicalPk = ed25519.getPublicKey(classicalSk);

  // Post-quantum: ML-DSA-65 (FIPS 204, NIST standard)
  const { publicKey: pqPk, secretKey: pqSk } = ml_dsa65.keygen(seed);

  return {
    classical: { publicKey: classicalPk, secretKey: classicalSk },
    quantum: { publicKey: pqPk, secretKey: pqSk }
  };
}

4. Resolution pipeline has five stages — parse, route, retrieve, validate, return:

export async function resolveDid(
  did: string,
  env: Env
): Promise<DidResolutionResult> {
  // Stage 1: Parse
  const parsed = parseDid(did);
  if (!parsed.ok) return invalidDidResult(did);

  // Stage 2: Route by namespace
  const backend = selectBackend(parsed.namespace);

  // Stage 3: Retrieve (KV cache first, Supabase fallback)
  const cached = await env.DID_CACHE.get(did, 'json') as DidDocument | null;
  if (cached) return successResult(cached, { source: 'cache' });

  const stored = await backend.fetchDocument(parsed, env);
  if (!stored) return notFoundResult(did);

  // Stage 4: Validate
  const validation = validateDocument(stored, parsed.namespace);
  if (!validation.ok) return invalidDocumentResult(did);

  // Stage 5: Cache + Return
  await env.DID_CACHE.put(did, JSON.stringify(stored), {
    expirationTtl: 3600  // 1h fresh, 24h stale-while-revalidate
  });

  return successResult(stored, { source: 'storage' });
}

Verifiable credentials anchor to the resolved DID. A TrustBadge credential is issued by the trust authority, carries the agent’s capabilities and trust score, signs with both classical and post-quantum keys, and supports revocation via StatusList2021. Both signatures must verify — a single-signature credential is rejected.

This article is the short version — W3C DIDs for AI Agents: Implementing did:tp: from Scratch is the full playbook.

Get the ebook — $29

Where this scales

The walkthrough above is the implementation spine. The full book covers six more dimensions:

  • Key rotation ceremonies — atomic rotation of both classical and post-quantum keys, the audit trail in the transparency log, and the operator-signed authorization that proves the rotation is legitimate.
  • Key recovery — operator-initiated recovery flow, the proof requirements, the delegation chain, and the cool-down window that prevents recovery abuse.
  • DID resolution caching — Cloudflare KV with 1h fresh + 24h stale-while-revalidate, the per-isolate LRU layer, the cache-busting on rotation/recovery/deactivation.
  • Verifiable Credentials integration — the TrustBadgeCredential schema, hybrid proof creation, presentation flow, trust chains (operator → agent), and StatusList2021 revocation.
  • Implementation reference — complete TypeScript SDK, Supabase schema with RLS, Cloudflare Worker handlers, libsodium + liboqs in a V8 isolate.
  • Testing and compliance — 89 W3C DID Core 1.0 conformance assertions, test vectors for parsing and signature verification, load-test results, and the production deployment checklist.

Every code listing in the book is production-grade TypeScript. The reference implementation runs live at trustauthority.ai. The 89 conformance assertions, the sub-50ms resolution latency, the hybrid-signature requirement — these are operational specifications, not aspirations.

Included with the book

  • did-generation-samples.ts — production-shaped TypeScript samples covering DID key generation, document assembly, DID-string construction, and the basic resolve/verify flow. MIT-licensed; drop into a Cloudflare Worker or Node service.

Get the full picture

The full playbook

W3C DIDs for AI Agents: Implementing did:tp: from Scratch — everything this article compresses, worked through end to end.

Get the ebook — $29

Readers of this also chose

Questions readers ask

Can I use did:tp: without trustauthority.ai?

Yes. The method specification is open. You can stand up your own resolver, your own trust authority, your own credential issuer. trustauthority.ai is the reference implementation we run, not a required dependency. The book covers the namespace, document, and resolution semantics so you can implement a compliant resolver against your own backend.

Why mandate dual signatures? Isn't Ed25519 still secure?

Ed25519 is secure today and for the foreseeable near-term against classical computers. It is not secure against a sufficiently large quantum computer running Shor's algorithm. The "harvest now, decrypt later" attack vector is real for long-lived credentials. ML-DSA-65 is the NIST FIPS 204 standard for post-quantum signatures. Mandating both is belt-and-suspenders: the classical signature keeps universal tooling compatibility today; the post-quantum signature is the credential that survives the transition.

How does this interact with did:web or did:key?

DID methods are designed to be interoperable. A verifier can resolve any DID method using a universal resolver. did:tp: is the agent-specific method with hybrid signatures and namespace semantics; did:web: and did:key: work for simpler cases (organization-owned domain, single keypair). The book covers the pattern for mapping between methods when interoperability is needed.

What's the cost to run a did:tp: resolver?

The reference implementation runs entirely on Cloudflare Workers + Supabase free tiers for typical first-year volume. Sub-50ms resolution latency globally. The KV cache covers >95% of resolution requests at the edge. Costs only appear when traffic exceeds the free tier thresholds.

What's the refund policy?

Lemon Squeezy's standard refund window applies. The refund link is in the receipt email.

Your opinion

Tell us anything.

What works, what doesn't, what's missing — especially about our watches, lenses, and the register itself. Anonymous is fine; leave an email if you'd like a reply.