Skip to main content
Version: v0.13

HTTP/WebSocket Transport

HTTP and WebSocket transports enable remote mDoc presentations over the network. These are used with TO_APP (reverse) engagement for online verification scenarios.

Use Cases

Remote transports are used for:

  • Online identity verification during account registration
  • Remote document verification for digital services
  • Integration with OID4VP presentation flows
  • Server-based verification without physical proximity

TO_APP Engagement with HTTP

The TO_APP engagement type uses HTTP-based retrieval:

val engagementManager = session.component.mdocEngagementManager

// Handle incoming mdoc:// URI from verifier
fun handleIncomingUri(uri: String) {
lifecycleScope.launch {
val result = engagementManager.toApp(
mdocUri = uri,
autoStart = true
)

when (result) {
is IdkResult.Success -> {
val engagement = result.value
handleEngagement(engagement)
}
is IdkResult.Failure -> {
showError(result.error)
}
}
}
}

URI Scheme Patterns

The toApp() method supports three URI patterns:

SchemeTransportDescription
mdoc: (opaque)BLE/NFCClassic reverse engagement
mdoc:// (hierarchical)REST APIWebsite/server retrieval
mdoc-openid4vp://OID4VPOAuth 2.0 integration

Protocol Flow

REST API Mode

Holder                              Verifier Server
│ │
│ 1. Parse mdoc:// URI │
│ │
│ 2. GET /request │
│────────────────────────────────────────►│
│ │
│ 3. 200 OK (DeviceRequest) │
│◄────────────────────────────────────────│
│ │
│ 4. User consent │
│ │
│ 5. POST /response (DeviceResponse) │
│────────────────────────────────────────►│
│ │
│ 6. 200 OK │
│◄────────────────────────────────────────│

Handling TO_APP Flow

Complete TO_APP flow with HTTP retrieval:

class ToAppHandler(
private val engagementManager: MdocEngagementManager,
private val documentProvider: DocumentProvider
) {
suspend fun handleUri(uri: String) {
// Create engagement from URI
val result = engagementManager.toApp(
mdocUri = uri,
autoStart = false
)

when (result) {
is IdkResult.Success -> {
val engagement = result.value

// Monitor engagement events
engagement.events.collect { event ->
when (event.state) {
is MdocEngagementState.Connected -> {
// Start transfer
val transferManager = engagement.start()

// Handle the transfer
val deviceRequest = transferManager.receiveDeviceRequest()
val approved = showConsentDialog(deviceRequest)

if (approved) {
val response = transferManager.createResponse(
deviceRequest = deviceRequest,
documentProvider = documentProvider
)
transferManager.sendDeviceResponse(response)
}
}
}
}
}
is IdkResult.Failure -> {
handleError(result.error)
}
}
}
}

OID4VP Integration

For mdoc-openid4vp:// URIs, the IDK integrates with OID4VP:

// OID4VP URIs are handled the same way
val uri = "mdoc-openid4vp://authorize?..."

val result = engagementManager.toApp(
mdocUri = uri,
autoStart = true
)

// The IDK handles the OID4VP protocol internally

Android

Register to handle mDoc URIs in AndroidManifest.xml:

<activity
android:name=".MdocHandlerActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mdoc" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mdoc-openid4vp" />
</intent-filter>
</activity>

iOS

Register URL schemes in Info.plist:

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>mdoc</string>
<string>mdoc-openid4vp</string>
</array>
</dict>
</array>

Monitoring Transfer State

Monitor HTTP-based transfer progress:

engagementManager.eventHub.allEvents.collect { event ->
when (event) {
is MdocEngagementEvent -> {
when (event.state) {
is MdocEngagementState.Connecting -> {
showMessage("Connecting to verifier...")
}
is MdocEngagementState.Connected -> {
showMessage("Connected")
}
is MdocEngagementState.Transferring -> {
showMessage("Transferring credentials...")
}
is MdocEngagementState.Completed -> {
showMessage("Transfer complete")
}
is MdocEngagementState.Error -> {
val error = (event.state as MdocEngagementState.Error).error
showError("Error: ${error.message}")
}
}
}
}
}

Error Handling

Handle network errors gracefully:

when (result) {
is IdkResult.Failure -> {
val error = result.error
val message = when {
error.message.contains("timeout", ignoreCase = true) ->
"Connection timed out. Please try again."
error.message.contains("network", ignoreCase = true) ->
"Network error. Check your connection."
error.message.contains("ssl", ignoreCase = true) ->
"Security error. The connection is not secure."
else -> error.message
}
showError(message)
}
}

Best Practices

When implementing HTTP/WebSocket transport:

  • Use HTTPS: Never use plain HTTP for credential exchange
  • Handle errors gracefully: Network requests can fail for many reasons
  • Set appropriate timeouts: Balance user experience with reliability
  • Validate server certificates: Ensure secure connections
  • Clean up on completion: Close engagements when transfer completes