Skip to main content
Version: v0.13

DID Management

The IDK provides a comprehensive DID management system for creating, updating, and deactivating DIDs with a fluent Kotlin DSL.

DID Manager​

The IDidManager interface provides lifecycle operations for DIDs:

OperationDescription
createCreate a new DID with generated or existing keys
updateModify a DID document (add/remove keys, services)
addKeyAdd a verification method to an existing DID
deactivateDeactivate a DID
listQuery stored DIDs with filters
findByDidFind a DID by its identifier
findByAliasFind a DID by alias

Creation DSL​

The IDK provides a Kotlin DSL for creating DIDs with a fluent, type-safe syntax.

Simple did:key​

import com.sphereon.did.manager.dsl.didCreateOptions
import com.sphereon.crypto.core.generic.KeyTypeMapping
import com.sphereon.crypto.core.generic.Curve
import com.sphereon.did.models.VerificationPurpose

val options = didCreateOptions {
method("key")
alias("my-signing-did")

autoGenerateKey {
keyType(KeyTypeMapping.OKP)
curve(Curve.Ed25519)
purposes(
VerificationPurpose.AUTHENTICATION,
VerificationPurpose.ASSERTION_METHOD
)
}
}

val result = didManager.create(options.options, options.keyConfigs)
println("Created: ${result.did}")
// Output: Created: did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK

did:jwk​

val options = didCreateOptions {
method("jwk")
alias("my-jwk-did")

autoGenerateKey {
keyType(KeyTypeMapping.EC)
curve(Curve.P_256)
purposes(VerificationPurpose.AUTHENTICATION)
}
}

val result = didManager.create(options.options, options.keyConfigs)
// Output: did:jwk:eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Ii...

did:web with Domain and Path​

val options = didCreateOptions {
method("web")
domain("example.com")
path("users", "alice") // Results in did:web:example.com:users:alice
alias("alice-did")

autoGenerateKey {
keyType(KeyTypeMapping.EC)
curve(Curve.P_256)
purposes(
VerificationPurpose.AUTHENTICATION,
VerificationPurpose.ASSERTION_METHOD
)
}

// Add service endpoints
service("website") {
type("LinkedDomains")
endpoint("https://alice.example.com")
}
}

val result = didManager.create(options.options, options.keyConfigs)

// After creation, publish the DID document:
// https://example.com/users/alice/did.json

Multiple Verification Methods​

For DIDs that need multiple keys (common with did:web):

val options = didCreateOptions {
method("web")
domain("example.com")

// Authentication key (Ed25519 for signatures)
verificationMethod("key-1") {
autoGenerateKey {
keyType(KeyTypeMapping.OKP)
curve(Curve.Ed25519)
kmsProvider("software") // Optional: specify KMS provider
}
purposes(VerificationPurpose.AUTHENTICATION)
}

// Assertion key (P-256 for credentials)
verificationMethod("key-2") {
autoGenerateKey {
keyType(KeyTypeMapping.EC)
curve(Curve.P_256)
}
purposes(VerificationPurpose.ASSERTION_METHOD)
}

// Key agreement (X25519 for encryption)
verificationMethod("key-3") {
autoGenerateKey {
keyType(KeyTypeMapping.OKP)
curve(Curve.X25519)
}
purposes(VerificationPurpose.KEY_AGREEMENT)
}

// Multiple services
service("hub") {
type("LinkedDomains")
endpoint("https://hub.example.com")
}

service("messaging") {
type("DIDCommMessaging")
endpoint("https://messaging.example.com")
}
}

Using Existing Keys​

Reference keys already stored in KMS:

val options = didCreateOptions {
method("web")
domain("example.com")

// Use existing key by alias
verificationMethod("key-1") {
useExistingKey {
alias("my-existing-signing-key")
providerId("aws-kms") // Optional: specify provider
}
purposes(VerificationPurpose.AUTHENTICATION)
}
}

Using an Existing JWK​

Create a DID from an existing public key:

val existingJwk = Jwk(
kty = JwaKeyType.EC,
crv = "P-256",
x = "WKn-ZIGevcwGFOMJ0GeEei2HpXXU6H0z...",
y = "y77t-RvAHRKTsSGd5KhPq8dJ7VhxqPxM..."
)

val options = didCreateOptions {
method("jwk")
useExistingKey(existingJwk)
alias("imported-key")
}

val result = didManager.create(options.options, options.keyConfigs)

DSL Reference​

DidCreateBuilder​

MethodDescription
method(name)DID method: "key", "jwk", "web"
alias(name)Human-readable alias
domain(domain)Domain for did:web
path(segments...)Path segments for did:web
controller(did)Controller DID (defaults to self)
autoGenerateKey { }Generate a new key via KMS
useExistingKey { }Use existing key by alias
useExistingKey(jwk)Use existing JWK directly
verificationMethod(id) { }Add named verification method
service(id) { }Add service endpoint

AutoGenerateKeyBuilder​

MethodDescription
keyType(type)KeyTypeMapping.OKP, EC, or RSA
curve(curve)Curve.Ed25519, P_256, P_384, etc.
algorithm(alg)Optional signature algorithm
kmsProvider(id)KMS provider ID
purposes(...)Verification purposes
verificationMethodId(id)Custom key ID

ExistingKeyByAliasBuilder​

MethodDescription
alias(name)Key alias in KMS
providerId(id)KMS provider ID
purposes(...)Verification purposes

ServiceBuilder​

MethodDescription
type(type)Service type (e.g., "LinkedDomains")
endpoint(url)Service endpoint URL
endpoint(map)Complex endpoint as map

Update DID​

Modify an existing DID document:

val updateResult = didManager.update(
did = "did:web:example.com",
options = DidUpdateOptions(
// Add a new service
addServices = listOf(
DidService(
id = "#messaging",
type = "DIDCommMessaging",
serviceEndpoint = "https://messaging.example.com"
)
),

// Remove services
removeServiceIds = listOf("#old-service"),

// Add verification methods
addVerificationMethods = listOf(
VerificationMethod(
id = "did:web:example.com#key-4",
type = "JsonWebKey2020",
controller = "did:web:example.com",
publicKeyJwk = newPublicKey
)
),

// Remove verification methods
removeVerificationMethodIds = listOf("#deprecated-key")
)
)

updateResult.fold(
success = { result ->
println("Updated: ${result.did}")
// For did:web, publish the updated document
},
failure = { error ->
println("Update failed: ${error.message}")
}
)

Add Key​

Add a verification method to an existing DID:

val addKeyResult = didManager.addKey(
did = "did:web:example.com",
options = AddKeyOptions(
publicKeyJwk = newPublicKey,
verificationMethodId = "key-5",
verificationMethodType = VerificationMethodType.JSON_WEB_KEY_2020,
purposes = listOf(VerificationPurpose.ASSERTION_METHOD)
)
)

Deactivate DID​

Mark a DID as deactivated:

val deactivateResult = didManager.deactivate(
did = "did:web:example.com",
options = DidDeactivateOptions(
reason = "Key compromise"
)
)

deactivateResult.fold(
success = { result ->
println("Deactivated: ${result.did}")

// For did:web, publish the deactivated document
val deactivatedDoc = result.deactivatedDocument
// Publish to https://example.com/.well-known/did.json
},
failure = { error ->
println("Deactivation failed: ${error.message}")
}
)

Persistence​

Storage Backends​

BackendUse CaseModule
MemoryTesting, ephemerallib-did-persistence-memory
SQLiteMobile, embeddedlib-did-persistence-sqlite
PostgreSQLEnterprise (EDK)EDK module

DidRepository API​

Direct access to DID storage:

val didRepository: DidRepository = session.component.didRepository

// Save a DID record
didRepository.save(didRecord).getOrThrow()

// Find by DID
val record = didRepository.findByDid("did:web:example.com").getOrNull()

// Find by alias
val record = didRepository.findByAlias("my-did").getOrNull()

// Query with filter
val records = didRepository.findAll(
DidRecordFilter(
method = "web",
role = DidRole.MANAGED
)
).getOrThrow()

// Update
didRepository.update(updatedRecord).getOrThrow()

// Delete
didRepository.delete("did:web:example.com").getOrThrow()

Key Mappings​

Track the relationship between verification methods and KMS keys:

// Get key mappings for a DID
val mappings = didRepository.getKeyMappings(didRecordId).getOrThrow()

mappings.forEach { mapping ->
println("Verification method: ${mapping.verificationMethodId}")
println("KMS key alias: ${mapping.kmsKeyAlias}")
println("KMS provider: ${mapping.kmsProviderId}")
println("Purposes: ${mapping.purposesJson}")
}

// Save a key mapping
didRepository.saveKeyMapping(
didRecordId = recordId,
mapping = DidKeyMappingRecord(
id = uuid(),
verificationMethodId = "#key-1",
kmsKeyAlias = "my-signing-key",
kmsProviderId = "software",
purposesJson = """["authentication", "assertionMethod"]"""
)
).getOrThrow()

// Delete key mappings
didRepository.deleteKeyMapping(mappingId)
didRepository.deleteKeyMappingsForDid(didRecordId)

Publishing did:web​

For did:web, you must publish the DID document to your web server:

val result = didManager.create(options.options, options.keyConfigs)
val didDocument = result.didDocument

// Serialize to JSON
val json = Json.encodeToString(didDocument)

// Publish to the correct URL based on the DID:
// did:web:example.com → https://example.com/.well-known/did.json
// did:web:example.com:users:alice → https://example.com/users/alice/did.json

// Example with Ktor client
httpClient.put("https://example.com/.well-known/did.json") {
contentType(ContentType.Application.Json)
setBody(json)
}

did:web URL Mapping​

DIDPublished URL
did:web:example.comhttps://example.com/.well-known/did.json
did:web:example.com:pathhttps://example.com/path/did.json
did:web:example.com:users:alicehttps://example.com/users/alice/did.json
did:web:example.com%3A8080https://example.com:8080/.well-known/did.json

REST API (Universal Registrar)​

The EDK provides REST APIs for DID management. See EDK Decentralized Identifiers.

EndpointDescription
POST /1.0/createCreate a new DID
POST /1.0/updateUpdate an existing DID
POST /1.0/deactivateDeactivate a DID
GET /1.0/methodsList supported methods
GET /1.0/propertiesGet capabilities

Platform Examples​

// Complete example: Create and use a DID
val didManager: IDidManager = session.component.didManager

// 1. Create DID
val createOptions = didCreateOptions {
method("key")
alias("signing-key")
autoGenerateKey {
keyType(KeyTypeMapping.OKP)
curve(Curve.Ed25519)
purposes(VerificationPurpose.ASSERTION_METHOD)
}
}

val createResult = didManager.create(
createOptions.options,
createOptions.keyConfigs
)
val did = createResult.did

// 2. Use DID for signing
val signCommand: SignJwsCommand = session.component.signJwsCommand
val signResult = signCommand.execute(
SignJwsArgs(
payload = "Hello, World!".encodeToByteArray(),
identifierOpts = ManagedIdentifierOpts(
method = IdentifierMethodDefaults.DID,
identifier = did
)
),
sessionContext
)

println("Signed JWS: ${signResult.getOrThrow().jws}")

Next Steps​