Skip to main content
Version: v0.25.0 (Latest)

Decentralized Identifiers

Decentralized Identifiers (DIDs) are the long-lived, self-controlled identifiers that anchor most of what runs through the EDK: issuer keys, verifier keys, holder bindings, OCA bundle authors, trust-list entries. Every DID resolves to a DID Document, which is the public artifact that other parties verify signatures against, look up service endpoints in, and use to bootstrap secure channels.

This section is about the REST surface the EDK provides on top of the IDK DID stack. It covers two things in particular:

  1. how a DID gets resolved and where the resolver fits in the call graph, and
  2. the two distinct REST APIs the EDK ships for creating and maintaining DIDs, what each one is good for, and how to pick between them.

The lower-level DID manager, providers, and DSL all live in the IDK and are documented under IDK DID Overview. This guide focuses on the REST-facing parts that you wire into a tenant deployment.

What ships with the EDK

The EDK builds on the IDK DID stack and adds the enterprise REST surface, persistence backends, and method providers needed for a production tenant.

ConcernModule(s)Notes
DID manager corelib-did-manager-public, lib-did-manager-implDID lifecycle, providers, filter, projections; lives in the IDK
Provider SPI and DSLlib-did-manager-publicDidProvider, didCreateOptions { ... }
Method providerslib-did-methods-key, lib-did-methods-jwk, lib-did-methods-web, lib-did-methods-webvh-*One module per supported DID method
Resolverlib-did-resolver-public, lib-did-resolver-implRegistry-based, accept-media-type aware, cache-enabled
Universal Resolver RESTlib-did-rest-resolver-serverDIF-compatible, base path /1.0
Universal Registrar RESTlib-did-rest-registrar-serverDIF-compatible, base path /1.0
Rich DID manager RESTservices-did-manager-restSphereon API, base path /api/dids/v1
Persistencelib-did-persistence-memory, lib-did-persistence-sqlite, lib-did-persistence-postgresql, lib-did-persistence-mysqlMemory and SQLite are IDK; PostgreSQL and MySQL ship with the EDK

The persistence split follows the wider IDK/EDK boundary: in-memory and SQLite stores live in the IDK so they work in any embedded scenario, while Postgres and MySQL ship with the EDK because they assume a JVM enterprise deployment.

Choosing between the two REST APIs

The EDK exposes two DID management REST surfaces over the same underlying DID manager. They serve different jobs and you typically enable the one that matches the consumer.

Two REST API surfaces over a shared DID manager

The Universal Registrar implements the DIF Universal Registrar spec. Five endpoints, document-level operations, and a stateless request and response shape that mirrors the spec line by line. It is the right choice when an existing tool, integration, or cross-vendor pipeline already speaks the DIF protocol, when you need predictable interop with non-Sphereon registrars, or when the operation you want to perform really is just "create / update / deactivate a document".

The rich DID manager API is a Sphereon-defined REST surface under /api/dids/v1. It exposes the same lifecycle operations plus everything the Universal Registrar omits: listing and filtering DIDs, paginating results, projecting only the fields you need, performing key-by-key changes through dedicated sub-resources, attaching aliases or equivalent identifiers, inspecting the KMS key mappings, and forcing or invalidating the resolved-document cache. It is the right choice for tenant admin UIs, internal control planes, automation that needs to enumerate DIDs, and any workflow that wants to mutate a single verification method, service, or controller without replaying the entire document.

The two surfaces are not exclusive. You can mount both in the same tenant: keep the rich API behind your internal ingress for operators, and expose the Universal Registrar through whichever path your DIF-speaking integration hits. They share state because they share the DID manager underneath.

For an at-a-glance comparison:

AspectUniversal RegistrarRich DID manager API
SpecificationDIF Universal Registrar 1.0Sphereon, documented in OpenAPI
Base path/1.0/api/dids/v1
Operations5 endpoints~50 endpoints across 10 sub-adapters
GranularityDocument-levelDocument + per-sub-resource
Listing / filteringNot in the specBuilt in (pagination, sort, expand, filter)
KMS key mapping inspectionHiddenFirst-class
Document cache controlImplicitExplicit (/document, /document/refresh, /document/cache)
Best fitCross-vendor interop, DIF-aware integrationsTenant admin UIs, automation, control planes

The dedicated pages cover each in detail:

  • Universal Registrar walks through the five DIF endpoints, request and response shapes, and how to wire it into a Spring Boot tenant.
  • Rich REST API covers the full /api/dids/v1 surface, the list filter, the expand projection, and the sub-resource endpoints that exist precisely because document-level PUT cannot preserve KMS invariants.

DID resolution

Resolution is the lookup step every credential issuance, verification, and trust evaluation depends on: take a DID, fetch its current DID Document, and use the public material in it. Unlike registration, resolution is read-only and almost always anonymous from the perspective of the host that publishes the document.

DID resolution path through the Universal Resolver, resolver registry, and method resolvers

The Universal Resolver REST surface is the same one that ships in the IDK. It exposes three endpoints under /1.0:

MethodPathPurpose
GET/1.0/identifiers/{identifier}Resolve a DID to its DID Document
GET/1.0/methodsList DID methods this resolver understands
GET/1.0/propertiesGet resolver capability metadata

GET /1.0/identifiers/{did} honors the standard Accept header so callers can ask for application/did+ld+json, application/did+json, or the result-envelope application/ld+json;profile="https://w3id.org/did-resolution". The response carries the resolved DID Document plus didResolutionMetadata and didDocumentMetadata envelopes, in line with the DIF resolution result schema.

Behind the endpoint sits the DID resolver registry. The registry inspects the method prefix (did:web, did:key, ...) and dispatches to the registered method resolver. Method resolvers come from the lib-did-methods-* modules and register themselves through the same SPI the DID manager uses for creation, which keeps creation and resolution in sync: if a method can be created, it can be resolved, with identical semantics.

What this means in practice:

  • did:key and did:jwk resolve locally, deriving the document from the identifier itself with no network call.
  • did:web resolves by fetching https://{domain}/.well-known/did.json (or the path-encoded equivalent), following the W3C did:web rules.
  • did:webvh resolves the verifiable history log from the publishing host and replays it to reconstruct the current document, validating each entry against the witness signatures.

The resolver caches results and honors invalidation: the cache is what /api/dids/v1/dids/{did}/document/refresh clears on the rich API, and what internal callers (issuer flows, OID4VP verifier bindings, trust evaluators) hit when they need the current public material for a DID without going back to the network on every call.

When to call resolution directly

Most EDK code does not call resolution explicitly. The issuer, the verifier, and the trust stack inject the DidResolver interface and rely on it transparently. Direct REST calls to /1.0/identifiers/{did} are mostly useful for:

  • diagnostic tooling that needs to see exactly what a third party would see when they look up your DID;
  • integrations from another runtime that cannot embed the IDK and needs an HTTP-shaped resolver;
  • cross-tenant or cross-host monitoring that periodically refreshes a published did:web document.

For the rich DID manager API, the GET /api/dids/v1/dids/{did}/resolve endpoint runs the same resolver but is scoped to a DID that is already tracked locally, which is convenient when you want resolution metadata alongside the locally-stored aliases, controllers, and key mappings.

Sub-pages