DID Method Registration JSON Specification
This document explains how JSON registration files following the official DID Registration specification (https://identity.foundation/did-registration/) are used to create DidMethod implementations in TrustWeave.
Overview
TrustWeave supports the official DID Method Registry format from identity.foundation/did-registration. The JSON file defines:
- Method Identity: The method name and metadata (name, status, specification, contact)
- Implementations: Available resolver services with
driverUrlpointing to resolver endpoints - Automatic Mapping: TrustWeave automatically maps registry entries to
HttpDidMethodimplementations
JSON to DidMethod Mapping
1. Method Identity
1
2
3
{
"name": "example"
}
Maps to:
1
2
3
4
5
6
7
class HttpDidMethod(
val registrationSpec: DidRegistrationSpec,
kms: KeyManagementService
) : AbstractDidMethod(registrationSpec.name, kms) {
// registrationSpec.name becomes the method identifier
override val method: String = "example"
}
The name field becomes the method identifier used in DID strings: did:example:123
2. Driver Configuration
The driver object determines how the DID method operations are implemented:
1
2
3
4
5
6
7
8
{
"driver": {
"type": "universal-resolver",
"baseUrl": "https://dev.uniresolver.io",
"protocolAdapter": "standard",
"timeout": 30
}
}
Maps to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Creates a UniversalResolver instance
private val universalResolver: UniversalResolver = createUniversalResolver()
private fun createUniversalResolver(): UniversalResolver {
val driver = registrationSpec.driver
val baseUrl = driver.baseUrl // "https://dev.uniresolver.io"
val protocolAdapter = createProtocolAdapter(driver.protocolAdapter) // "standard"
val timeout = driver.timeout ?: 30
return DefaultUniversalResolver(
baseUrl = baseUrl,
timeout = timeout,
protocolAdapter = protocolAdapter
)
}
Driver Types:
universal-resolver: Creates aDefaultUniversalResolverthat delegates to an external Universal Resolver instancenative: Requires custom code (not supported via JSON)custom: Requires additional configuration (not supported via JSON)
3. Capabilities Mapping
The capabilities object maps directly to DidMethod interface methods:
1
2
3
4
5
6
7
8
{
"capabilities": {
"create": false,
"resolve": true,
"update": false,
"deactivate": false
}
}
Maps to DidMethod Interface:
| JSON Field | DidMethod Method | Implementation |
|---|---|---|
capabilities.create |
createDid(options) |
Throws exception if false, otherwise delegates (not yet implemented) |
capabilities.resolve |
resolveDid(did) |
Delegates to UniversalResolver.resolveDid() if true |
capabilities.update |
updateDid(did, updater) |
Throws exception if false, otherwise delegates (not yet implemented) |
capabilities.deactivate |
deactivateDid(did) |
Throws exception if false, otherwise delegates (not yet implemented) |
Example Implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
override suspend fun resolveDid(did: String): DidResolutionResult {
val capabilities = registrationSpec.capabilities
if (capabilities?.resolve != true) {
throw TrustWeaveException("DID method does not support resolution.")
}
// Validate DID format matches method name
require(did.startsWith("did:${registrationSpec.name}:")) {
"Invalid DID format for method '${registrationSpec.name}': $did"
}
// Delegate to Universal Resolver
return universalResolver.resolveDid(did)
}
Complete Flow: JSON → DidMethod
Step 1: Parse JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
val jsonString = """
{
"name": "web",
"driver": {
"type": "universal-resolver",
"baseUrl": "https://dev.uniresolver.io"
},
"capabilities": {
"resolve": true
}
}
"""
val spec = DidRegistrationSpecParser.parse(jsonString)
// Creates: DidRegistrationSpec(name="web", driver=DriverConfig(...), capabilities=MethodCapabilities(resolve=true))
Step 2: Create DidMethod Instance
1
2
3
4
5
val method = HttpDidMethod(spec, kms)
// Creates a DidMethod with:
// - method = "web"
// - universalResolver = DefaultUniversalResolver("https://dev.uniresolver.io")
// - capabilities = MethodCapabilities(resolve=true)
Step 3: Register and Use
1
2
3
4
5
6
registry.register(method)
// Now you can use it
val result = registry.resolve("did:web:example.com")
// Internally calls: method.resolveDid("did:web:example.com")
// Which calls: universalResolver.resolveDid("did:web:example.com")
Field Reference
Required Fields
| Field | Type | Description | Maps To |
|---|---|---|---|
name |
string | DID method name | DidMethod.method property |
driver |
object | Driver configuration | HttpDidMethod.resolver |
Optional Fields
| Field | Type | Description | Maps To |
|---|---|---|---|
status |
string | Implementation status | Metadata only |
specification |
string (URI) | Spec URL | Metadata only |
contact |
object | Contact info | Metadata only |
capabilities |
object | Supported operations | DidMethod method implementations |
driver.baseUrl |
string (URI) | Universal Resolver URL | DefaultUniversalResolver.baseUrl |
driver.protocolAdapter |
string | Protocol adapter name | DefaultUniversalResolver.protocolAdapter |
driver.timeout |
integer | Request timeout | DefaultUniversalResolver.timeout |
driver.apiKey |
string | API key | DefaultUniversalResolver.apiKey |
Implementation Details
HttpDidMethod Class
The HttpDidMethod class implements the DidMethod interface:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class HttpDidMethod(
val registrationSpec: DidRegistrationSpec,
kms: KeyManagementService
) : AbstractDidMethod(registrationSpec.name, kms) {
// Created from driver.baseUrl and driver.protocolAdapter
private val resolver: UniversalResolver = createResolver()
// Implements DidMethod.resolveDid() if capabilities.resolve == true
override suspend fun resolveDid(did: String): DidResolutionResult {
// Validates capabilities.resolve
// Validates DID format matches method name
// Delegates to resolver.resolveDid() (HTTP endpoint)
}
// Throws exception if capabilities.create == false
override suspend fun createDid(options: DidCreationOptions): DidDocument {
// Currently not implemented for JSON-registered methods
}
// Similar for updateDid() and deactivateDid()
}
Protocol Adapters
The driver.protocolAdapter field determines which protocol adapter is used:
"standard": UsesStandardUniversalResolverAdapter(default)- Endpoint:
/1.0/identifiers/{did} - Used by: dev.uniresolver.io, most Universal Resolver instances
- Endpoint:
"godiddy": UsesGodiddyProtocolAdapter(requires godiddy plugin)- Endpoint:
/1.0.0/universal-resolver/identifiers/{did} - Used by: GoDiddy service
- Endpoint:
Limitations
-
Resolution Only: Currently, only
resolveDid()is fully implemented. Other methods (createDid,updateDid,deactivateDid) require native implementations. -
Universal Resolver Dependency: JSON-registered methods require an external Universal Resolver instance that supports the method.
-
Protocol Adapters: Only “standard” and “godiddy” adapters are supported. Custom adapters require code.
Example: Complete JSON → DidMethod
Input JSON:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "ion",
"status": "implemented",
"specification": "https://identity.foundation/ion/",
"driver": {
"type": "universal-resolver",
"baseUrl": "https://dev.uniresolver.io",
"protocolAdapter": "standard",
"timeout": 30
},
"capabilities": {
"resolve": true
}
}
Resulting DidMethod:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Equivalent to:
val method = HttpDidMethod(
registrationSpec = DidRegistrationSpec(
name = "ion",
status = "implemented",
specification = "https://identity.foundation/ion/",
driver = DriverConfig(
type = "universal-resolver",
baseUrl = "https://dev.uniresolver.io",
protocolAdapter = "standard",
timeout = 30
),
capabilities = MethodCapabilities(resolve = true)
),
kms = kms
)
// method.method == "ion"
// method.resolveDid("did:ion:...") delegates to Universal Resolver
Validation
The JSON is validated against the schema (schema.json) when parsed. Invalid JSON will throw an IllegalArgumentException with details about the validation error.