LogoLogo
  • Platform Overview
  • 🗺️Guides
    • Getting Started
    • Users
      • Integrate the User SDK
      • Registration
      • Authentication
      • SDK Releases
      • API Reference
    • Entitlements
      • Administrative API
        • Integrating the Administrative API
        • Entitlement Definitions
        • Managing Entitlements Sets
        • Managing Entitlements Sequences
        • Managing User Entitlements
        • API Schema
      • End-user API
        • Integrate the Entitlements SDK
        • Redeeming Entitlements
        • Retrieving Entitlements
        • SDK Releases
        • API Reference
    • Sudos
      • Integrate the Sudo Profiles SDK
      • Sudo Entitlements
      • Manage Sudos
      • SDK Releases
      • API Reference
    • Telephony
      • Integrate the Telephony SDK
      • Manage Phone Numbers
      • Text Messaging
      • Voice Calling
      • Telephony Simulator
      • SDK Releases
      • API Reference
    • Email
      • Integrate the Email SDK
      • Email Entitlements
      • Manage Email Addresses
      • Sending & Receiving Email
      • Manage Email Folders
      • Draft Email Messages
      • Manage Email Address Blocklists
      • Email Address Public Information
      • Pagination
      • Caching
      • Configuration Data
      • Email Notifications
      • SDK Releases
      • API Reference
    • Decentralized Identity
      • Edge Agent
        • Relay SDK
          • Integrate the Relay SDK
          • Relay Entitlements
          • Manage Relay Postboxes
          • Manage Relay Messages
          • Receiving Messages
          • SDK Releases
        • Edge Agent SDK
          • Integrate the Edge Agent SDK
          • Agent Management
          • Manage Wallets
          • Establishing Connections
          • Manage Connections
          • Messaging
          • Manage DIDs
          • Accepting New Credentials
          • Manage Credentials
          • Present Credentials for Verification
          • Utilize Alternative Cryptography Providers
          • SDK Releases
          • Standards and Protocols
      • Cloud Agent
        • Cloud Agent Admin API
          • Integrate the Cloud Agent Admin API
          • Aries Interop Profile (AIP)
            • Connection Exchanges
            • Credential Exchanges
            • Proof Exchanges
          • Connections
          • Basic Messages
          • Credentials
            • Anoncreds Credentials
              • Schemas
              • Credential Definitions
            • W3C Credentials
          • Audit Logs
          • API Schema
          • Error Codes
          • Standards and Protocols
    • Virtual Cards
      • Integrate the Virtual Cards SDK
      • Virtual Cards Entitlements
      • Virtual Cards Transaction Velocity Constraints
      • Key Management
      • Manage Funding Sources
      • Manage Virtual Cards
      • Manage Transactions
      • Configuration Data
      • Pagination
      • Caching
      • SDK Releases
      • API Reference
    • Virtual Cards Simulator
      • Integrate the Virtual Cards Simulator SDK
      • Simulate Authorizations
      • Simulate Debits
      • Simulate Refunds
      • Simulate Reversals
      • Merchants and Currencies
      • SDK Releases
      • API Reference
    • Virtual Private Network
      • Integrate the VPN SDK
      • VPN Entitlements
      • Manage Servers
      • Manage Connection
      • Observe VPN Related Events
      • SDK Releases
      • API Reference
      • Frequently Asked Questions
    • Secure ID Verification
      • Integrate the Secure ID Verification SDK
      • List Supported Countries
      • Verify an Identity
      • Check Secure ID Verification Status
      • Use the Secure ID Verification Simulator
      • SDK Releases
      • API Reference
    • Password Manager
      • Integrate the Password Manager SDK
      • Accessing the Password Manager
      • Managing Password Vaults
      • Managing Password Vault Items
      • Vault Import and Export
      • Password Utilities
      • Password Manager Entitlements
      • Password Vault Security
      • SDK Releases
      • API Reference
    • Ad/Tracker Blocker
      • Integrate the Ad/Tracker Blocker SDK
      • Manage Rulesets
      • Blocking Ads and Trackers
      • Manage Exceptions
      • SDK Releases
      • API Reference
    • Site Reputation
      • Integrate the Site Reputation SDK
      • Use the Site Reputation SDK
      • SDK Releases
      • API Reference
  • 💡Concepts
    • Sudo Digital Identities
  • 🧱Development
    • Versioning
  • 🏢Administration
    • Admin Console Roles
  • ❓Get Help
    • Request a Demo
    • Report an Issue
Powered by GitBook
On this page
  • Initializing an Agent
  • Configuration
  • Builder
  • Changing Agent Configuration
  • Receiving a URL Request
  • Receiving a DIDComm Message
  • Running DIDComm Agent Management
  • DIDComm Message Sources
  • Relay Message Source
  • Other Provided Message Sources
  • Subscribe to Events
  • Managing Ledger Cache
  1. Guides
  2. Decentralized Identity
  3. Edge Agent
  4. Edge Agent SDK

Agent Management

Manage instances of mobile agents encapsulating DI protocol engagements and wallet data

PreviousIntegrate the Edge Agent SDKNextManage Wallets

Last updated 2 months ago

The Edge Agent SDK revolves around instances of SudoDIEdgeAgents. Agent instances provide access to modules for accessing data or DI protocol engagements. As well as APIs for managing the agent's configuration, managing the message receiver loop, and hooks for subscribing to agent events.

Initializing an Agent

Configuration

Before initializing an agent, an AgentConfiguration object must be created to dictate some of the agent's behavior. Using the fields in AgentConfiguration, the following agent behavior can be configured:

Required:

  • networkConfiguration controls how the agent should handle network interactions and which ledgers the agent should opt-in to. This configuration allows tweaking of general network settings (such as ledger re-try attempts), and ledger-specific configurations for the Edge Agent's supported ledger types: Cheqd and Sovrin-based (did:sov + unqualified indy DIDs). The configurations for these ledgers will be used when resolving DIDs or Anoncreds objects from those ledgers during protocols. For ledger-specific configurations, null can be explicitly provided to opt-out of that ledger type if it's not needed by the agent.

Optional:

  • storageDirectory can be used to specify a directory location on the device where agent data will be stored. If null is provided (or if unprovided), a persistent data directory within the application's environment will be used.

  • peerConnectionConfiguration is the default configuration for how the agent should present itself to peers it connects with. It includes a label field for a self-assigned unverified label or nickname.

  • exchangePreservationConfiguration controls preservation of exchange records in the wallet after a protocol (connection, credential or proof presentation protocols) is complete.

  • cacheConfiguration controls how the agent should cache different data it uses (such as immutable data it receives from the ledger it uses).

  • + more. The configurable parameters on the agent are growing over time. To see the full set of configurable fields, please refer to the .

Builder

To initialize a SudoDIEdgeAgent, the associated Builder class can be used along with the configuration you wish to use ().

An AgentConfiguration must be set in the builder. A logger can also optionally be set.

The following example demonstrates how to build an agent using a default configuration.

let genesisFile: URL // a URL pointing to a indy-ledger genesis file on disk

let networkConfiguration = NetworkConfiguration(
    sovConfiguration: NetworkConfiguration.Sov(
        genesisFiles: [genesisFile],
        namespace: "testnet"
    ),
    cheqdConfiguration: NetworkConfiguration.Cheqd()
)
let agentConfiguration = AgentConfiguration(networkConfiguration: networkConfiguration)
agent = try SudoDIEdgeAgentBuilder()
            .setAgentConfiguration(agentConfiguration: agentConfiguration)
            .build()

Note that only agentConfiguration and context are required to be set in the Builder. A custom logger and dispatcher for coroutine methods can be passed into the builder if desired as well.

val appContext: Context // Android application context
val genesisFile: File // a File reference to a indy-ledger genesis file on disk

val networkConfiguration = NetworkConfiguration(
    sovConfiguration = NetworkConfiguration.Sov(
        genesisFiles = listOf(genesisFile),
        namespace = "testnet"
    ),
    cheqdConfiguration = NetworkConfiguration.Cheqd()
)

val agentConfiguration = AgentConfiguration(
    networkConfiguration = networkConfiguration
)

val agent: SudoDIEdgeAgent = SudoDIEdgeAgent.builder()
    .setContext(appContext)
    .setAgentConfiguration(agentConfiguration)
    .build()

This builder also notably allows for custom cryptography providers to be injected into the agent, such that the agent can utilize this provider during operations such as DID creation and presentation signing. For high assurance use cases, we also provide default cryptography providers that utilize iOS and Android Hardware security.

Please see Utilize Alternative Cryptography Providers for guidance.

Changing Agent Configuration

let agent: SudoDIEdgeAgent // agent to change configuration for
let newConfiguration: AgentConfiguration // the new configuration to set the agent to

try agent.setAgentConfiguration(agentConfiguration: newConfiguration)
val agent: SudoDIEdgeAgent // agent to change configuration for
val newConfiguration: AgentConfiguration // the new configuration to set the agent to

agent.setAgentConfiguration(newConfiguration)

Some configuration fields should not be changed whilst an agent has a wallet open. The SDK inline code documentation notes these fields. These fields include storageDirectory and networkConfiguration. To reconfigure these fields on an agent, it is recommended to stop the agent's run loop, close the wallet and re-initialize the agent before setting a new config for these values.

Receiving a URL Request

As part of the protocols supported by the Edge Agent, external requests (from Issuers, Verifiers, etc) are often made to the Wallet App in the form of a URL request. For instance, a deep link to the app or a QR Code scanned by the app. The Edge Agent API receiveUrl can be used to process these incoming URL requests.

The following request types are supported:

When a URL is successfully processed and received by the agent, the agent's data state is updated, and a corresponding event may trigger (see Subscribe to Events). After this, and depending on the type of request received, the agent may be ready to respond to the request via protocol interactions (refer to later relevant sections in this documentation such as Establishing Connections, Accepting New Credentials & Present Credentials for Verification).

let agent: SudoDIEdgeAgent
let requestUrl: String // string URL received from some channel (QR Code, deep link)

do {
    try await agent.receiveUrl(url: requestUrl)
} catch {
    // handle error
}
val agent: SudoDIEdgeAgent
val requestUrl: String // string URL received from some channel (QR Code, deep link)

launch {
    try {
        agent.receiveUrl(requestUrl)
    } catch (e: ReceiveUrlException) {
        // handle exception
    }
}

How URL requests are captured before being passed into the receiveUrl API is a responsibility of the application itself. The application may wish to register known deep link schemes for the application, or implement a QR Code scanner.

Receiving a DIDComm Message

With an instantiated SudoDIEdgeAgent, you are ready to begin receiving and processing DIDComm messages. The agent API receiveMessage can be used to receive supported Aries RFC DIDComm messages. Typically, the messages passed into receiveMessage are encrypted (Aries RFC 0019) and come from some communication channel with a peer (e.g. via a Relay or Mediator source). However, some non-encrypted messages are supported as well, most notably Connection invitations received through some other channel (e.g. out of band channels).

let agent: SudoDIEdgeAgent
let rawMessage: Data // bytes of a raw DIDComm message received from some channel
let metadata: ReceivedMessageMetadata // metadata of the received DIDComm message. Usually generated by the message source

do {
    try await agent.receiveMessage(
        rawMessage: rawMessage,
        metadata: metadata
    )
} catch {
    // handle error
}
val agent: SudoDIEdgeAgent
val rawMessage: ByteArray // bytes of a raw DIDComm message received from some channel 
val metadata: ReceivedMessageMetadata // metadata of the received DIDComm message. Usually generated by the message source

launch {
    try {
        agent.receiveMessage(rawMessage, metadata)
    } catch (e: ReceiveMessageException) {
        // handle exception
    }
}

The receiveMessage API allows for manual processing of messages to be achieved. If automatic message receiving and processing is desired, configuring a MessageSource and using the agent run method will be more fitting for this use case (see below).

Running DIDComm Agent Management

Note that similar to receiveMessage, the agent must have a wallet open before starting the run loop. Additionally, only one run loop for an agent can be run at once.

The run loop performs any pre-checks and then begins the loop (polling the MessageSource in a background task). The API can be called like so:

let agent: SudoDIEdgeAgent
let messageSource: MessageSource // some implementation of a MessageSource

do {
    try agent.run(messageSource: messageSource)
} catch {
    // handle error
}
val agent: SudoDIEdgeAgent
val messageSource: MessageSource // some implementation of a MessageSource

try {
    agent.run(messageSource)
} catch (e: AgentRunException) {
    // handle exception
}

After an agent is running, several APIs can be used to manage the run loop. These APIs are:

  • isRunning(): Boolean - reports whether the agent is actively running and not attempting to stop. False indicates that the loop is stopped.

  • stop() - triggers the agent to begin its stop sequence (finishing whatever message it was processing, if any)

  • isStopping(): Boolean - reports whether the agent is in the stop sequence (as requested via stop()).

DIDComm Message Sources

The agent's run loop is powered by implementations of the MessageSource interface. As a consumer, you can choose to implement your own message source, or use our provided implementations.

To implement your own MessageSource, all you need to implement is 2 methods - getMessage(): Message? and finalizeMessage(id: String). Quite simply, your implementation of getMessage should attempt to fetch the next available Message from your message source channel, and then finalizeMessage should take the provided id (from Message.id) and make the necessary action to 'finalize' or remove the message from the message source). The message body returned by the getMessage call should encrypted or unencrypted Aries DIDComm messages.

Relay Message Source

let relayClient: SudoDIRelayClient
let logger: Logger

let messageSource = SudoDIRelayMessageSource(relayClient: relayClient, logger: logger)

do {
    try agent.run(messageSource: messageSource)
} catch {
    // handle error
}
val relayClient: SudoDIRelayClient
val logger: SudoLogger

val messageSource = SudoDIRelayMessageSource(relayClient, logger)

try {
    agent.run(messageSource)
} catch (e: AgentRunException) {
    // handle exception
}

Other Provided Message Sources

In addition to the relay message source, you may use a URL DIDComm message processing message source (UrlMessageSource) and a simple aggregator message source (RoundRobinMultiMessageSource).

let logger: Logger 
let urlEncodedMessage: String // (e.g. from scanning an invitation QR code)

let messageSource = UrlMessageSource(logger: logger)

do {
    try agent.run(messageSource: messageSource)
} catch {
    // handle error
}

do {
    try await messageSource.queueUrlMessage(url: urlEncodedMessage)
} catch {
    // handle error
}
val logger: SudoLogger 
val urlEncodedMessage: String // (e.g. from scanning an invitation QR code)

val messageSource = UrlMessageSource(logger)

try {
    agent.run(messageSource)
} catch (e: AgentRunException) {
    // handle exception
}

launch {
    try {
        messageSource.queueUrlMessage(urlEncodedMessage)
    } catch (e: QueueUrlMessageException) {
        // handle exception
    }
}

The RoundRobinMultiMessageSource can be used to aggregate together multiple message sources. As the name implies, the implementation simply polls the MessageSources it has been given in a fair round-robin approach. For more use-case specific aggregations of MessageSources, a custom implementation may be more suitable.

The RoundRobinMultiMessageSource can be used like so:

let urlMessageSource: UrlMessageSource
let relayMessageSource: SudoDIRelayMessageSource
let logger: Logger

let multiMessageSource = RoundRobinMultiMessageSource(logger: logger)
multiMessageSource.addMessageSource(messageSource: urlMessageSource)
multiMessageSource.addMessageSource(messageSource: relayMessageSource)

do {
    try agent.run(messageSource: multiMessageSource)
} catch {
    // handle error
}
val urlMessageSource: UrlMessageSource
val relayMessageSource: SudoDIRelayMessageSource
val logger: SudoLogger

val multiMessageSource = RoundRobinMultiMessageSource(logger)
multiMessageSource.addMessageSource(urlMessageSource)
multiMessageSource.addMessageSource(relayMessageSource)

try {
    // agent.run will call `getMessage` on the `multiMessageSource`, which will
    // alternate between calling the `urlMessageSource` and `relayMessageSource`
    // message sources it was provided in this example.
    agent.run(multiMessageSource)
} catch (e: AgentRunException) {
    // handle exception
}

Subscribe to Events

It is important for consuming applications to be aware of updates to the agent's protocol states in real-time, rather than polling for updates. Important protocol state updates and events include:

  • A new incoming Connection establishment request, or an update to an existing Connection establishment protocol

  • A new incoming Credential offer from a credential Issuer, or an update to an existing Credential exchange protocol

  • A new incoming Credential Presentation request from a credential Verifier, or an update to an existing Presentation exchange protocol

  • A new incoming basic message from a connection

These state changes can be subscribed to via the subscribeToAgentEvents API. This API takes an implementation of AgentEventSubscriber, which has methods that will be invoked on different event types.

The subscribeToAgentEvents API can be called multiple times to attach many subscribers. Each call to the API will return a unique String identifier, which can be passed into unsubscribeToAgentEvents in order to remove the subscriber from receiving event updates. unsubscribeAll is an API that can also be used to quickly remove all subscribers from receiving event updates.

class CustomSubscriber : AgentEventSubscriber {
    func connectionExchangeStateChanged(connectionExchange: ConnectionExchange) {
        // the following will be invoked whenever a connection protocol state change occurs.
        // ConnectionExchange will contain the updated state
        print("connection update: \(connectionExchange)")
    }
    func credentialExchangeStateChanged(credentialExchange: CredentialExchange) {
        // the following will be invoked whenever a credential issuance protocol state change occurs.
        // CredentialExchange will contain the updated state
        print("credential update: \(credentialExchange)")
    }
    func proofExchangeStateChanged(proofExchange: ProofExchange) {
        // the following will be invoked whenever a proof presentation protocol state change occurs.
        // ProofExchange will contain the updated state
        print("proof update: \(proofExchange)")
    }
    func inboundBasicMessage(basicMessage: BasicMessage.Inbound) {
        // the following will be invoked whenever a new basic message is received.
        print("new message: \(basicMessage)")
    }
    func messageProcessed(messageId: String) {
        // the following will be invoked whenever the agent run loop processes a new message.
        print("message processed: \(messageId)")
    }
}


let customSubscriber = CustomSubscriber()
let subscriberId = agent.subscribeToAgentEvents(subscriber: customSubscriber)
let subscriberId: String // captured from `subscribeToAgentEvents`
agent.unsubscribeToAgentEvents(subscriptionId: subscriberId)
agent.unsubscribeAll()
val subscriber = object : AgentEventSubscriber {
    override fun connectionExchangeStateChanged(connectionExchange: ConnectionExchange) {
        // the following will be invoked whenever a connection protocol state change occurs.
        // ConnectionExchange will contain the updated state
        println("connection update: $connectionExchange")
    }
    override fun credentialExchangeStateChanged(credentialExchange: CredentialExchange) {
        // the following will be invoked whenever a credential issuance protocol state change occurs.
        // CredentialExchange will contain the updated state
        println("credential update: $credentialExchange")
    }
    override fun proofExchangeStateChanged(proofExchange: ProofExchange) {
        // the following will be invoked whenever a proof presentation protocol state change occurs.
        // ProofExchange will contain the updated state
        println("proof update: $proofExchange")
    }
    
    override fun inboundBasicMessage(basicMessage: BasicMessage.Inbound) {
        // the following will be invoked whenever a new basic message is received.
        println("new message: $basicMessage")
    }
}

val subscriberId = agent.subscribeToAgentEvents(subscriber)
val subscriberId: String // captured from `subscribeToAgentEvents`
agent.unsubscribeToAgentEvents(subscriberId)
agent.unsubscribeAll()

Managing Ledger Cache

If caching is being used, you can clear the cache at your own discretion via the clearLedgerCache API. This API will succeed regardless of whether any cache was cleared or not.

let agent: SudoDIEdgeAgent

do {
    try await agent.clearLedgerCache()
} catch {
    // handle error
}
val agent: SudoDIEdgeAgent

launch {
    try {
        agent.clearLedgerCache()
    } catch (e: ClearLedgerCacheException) {
        // handle exception
    }
}

After an , the configuration can be changed on the fly if desired. This can be achieved via the setAgentConfiguration API. This will allow certain behavior, such as credential auto acceptance, agent connection appearance, and more to be changed.

: via the openid-credential-offer:// URL scheme

: via the openid4vp:// or openid:// URL scheme

: explicitly via the didcomm:// URL scheme, or as a fallback for when other known schemes are not caught

Most URLs will only be processable if the agent has their wallet storage open before receiving. Please see the on wallet management.

See our as a reference.

Most messages will only be processable if the agent has their wallet storage open before receiving a message. Please see the on wallet management.

In addition to , the agent can be run in a loop to poll for and process messages that come in via a MessageSource. Information on MessageSources and using the default provided implementations can be .

Our provided MessageSources, particularly , can be used as a reference for designing your own MessageSource.

To integrate the Edge Agent SDK with our , you can use the SudoDIRelayMessageSource implementation. The SudoDIRelayMessageSource can be created using the constructor:

To get a SudoDIRelayClient instance, please refer to the

The UrlMessageSource can be used to parse and queue DIDComm messages that are encoded in a URL (i.e. an , or a ). These messages can be passed into the queueUrlMessage method to queue them for usage in the agent:

As a decentralized identity agent, lots of read requests to ledgers to retrieve immutable data are performed. These read requests can be costly depending on the reception of nodes on the ledger network. To help reduce this cost, the agent features APIs to help management the caching of these ledger read requests. As mentioned , the agent configuration contains a field to turn on or off caching of immutable ledger data. By default, caching is turned on.

🗺️
OpenID4VCI Credential Offers
OpenID4VP Authorization Requests
Out of Band DIDComm message
documentation
sample apps
documentation
Sudo DI Relay SDK
Sudo DI Relay SDK integration documentation
Out of Band 0434 Message
Connection Protocol 0160 Invitation
API Reference
see above
agent is initialized
manually receiving DIDComm messages
found below
Relay Message Source
above