Sep45Client Domain Signing Delegate
Delegate for signing a single authorization entry with client domain credentials.
SEP-45 supports client domain verification, where a client domain's signing key signs one of the authorization entries to prove the client is authorized by that domain. This is useful for wallet applications that want to prove their association with a specific domain (e.g., "wallet.example.com").
This delegate enables integration with:
Wallet backend servers: Remote signing services that hold custody of domain keys
Hardware Security Modules (HSMs): Enterprise key management systems
Cloud KMS services: AWS KMS, Google Cloud KMS, Azure Key Vault
Multi-Party Computation systems: Distributed key signing
Design Note
This interface uses String-based API (base64 XDR) instead of object-based API because remote signing services communicate via HTTP with base64-encoded XDR. This eliminates unnecessary encode/decode cycles in the common case where the signing happens on a remote server.
Implementation Requirements
The implementation should:
Decode the base64 XDR to com.soneso.stellar.sdk.xdr.SorobanAuthorizationEntryXdr (if needed for inspection)
Set
signatureExpirationLedgeroncredentials.addressCredentialsSign the entry using the client domain's private key
Encode back to base64 XDR
Example: Remote Signing Server
val delegate = Sep45ClientDomainSigningDelegate { entryXdr ->
// POST to remote signing server
val response = httpClient.post("https://signing.example.com/sign") {
contentType(ContentType.Application.Json)
setBody("""{"entry": "$entryXdr", "network": "testnet"}""")
}
val json = Json.parseToJsonElement(response.bodyAsText()).jsonObject
json["signed_entry"]?.jsonPrimitive?.content
?: throw Exception("Signing failed: ${response.bodyAsText()}")
}
val token = webAuth.jwtToken(
clientAccountId = contractId,
signers = listOf(clientSigner),
clientDomain = "wallet.example.com",
clientDomainSigningDelegate = delegate
)Example: Local Signing with KeyPair
val clientDomainKeyPair = KeyPair.fromSecretSeed("S...")
val delegate = Sep45ClientDomainSigningDelegate { entryXdr ->
// Decode XDR
val entry = SorobanAuthorizationEntryXdr.fromXdrBase64(entryXdr)
// Sign using Auth helper
val signedEntry = Auth.authorizeEntry(
entry = entry,
signer = clientDomainKeyPair,
validUntilLedgerSeq = expirationLedger,
network = Network.TESTNET
)
// Encode back to base64
signedEntry.toXdrBase64()
}Security Considerations
The signing key should be kept secure and never transmitted
Use HTTPS for remote signing servers
Consider using bearer tokens or mTLS for authentication
Validate the entry before signing (check contract address, function name)
See also
for usage with client domain authentication
for signing authorization entries