Skip to main content
Version: v0.13

Device Request and Response

The ISO 18013-5 protocol uses DeviceRequest and DeviceResponse structures to exchange credential data. This guide explains their structure and how to work with them in the IDK.

DeviceRequest Structure

A DeviceRequest specifies what data the verifier is requesting:

DeviceRequest = {
version: "1.0",
docRequests: [DocRequest, ...]
}

DocRequest = {
docType: "org.iso.18013.5.1.mDL",
itemsRequest: {
nameSpaces: {
"org.iso.18013.5.1": {
"family_name": true,
"given_name": true,
...
}
}
},
readerAuth: ReaderAuthentication (optional)
}

Parsing Device Requests

val deviceRequest: DeviceRequest = transferManager.receiveDeviceRequest()

// Iterate over document requests
for (docRequest in deviceRequest.docRequests) {
val docType = docRequest.docType // e.g., "org.iso.18013.5.1.mDL"
val itemsRequest = docRequest.itemsRequest

// Iterate over namespaces
for ((namespace, elements) in itemsRequest.nameSpaces) {
// Iterate over requested elements
for ((elementId, intentToRetain) in elements) {
println("Requested: $docType / $namespace / $elementId")
println(" Intent to retain: $intentToRetain")
}
}
}

DeviceResponse Structure

A DeviceResponse contains the requested data with cryptographic proofs:

DeviceResponse = {
version: "1.0",
documents: [Document, ...],
status: 0
}

Document = {
docType: "org.iso.18013.5.1.mDL",
issuerSigned: IssuerSigned,
deviceSigned: DeviceSigned
}

IssuerSigned Data

Data signed by the credential issuer, containing the Mobile Security Object (MSO) and namespace data:

val document = deviceResponse.documents?.first()
val issuerSigned: IssuerSigned = document?.issuerSigned!!

// Mobile Security Object
val mso: MobileSecurityObject = issuerSigned.MSO

// Device key info from MSO
val deviceKeyInfo: DeviceKeyInfoCbor = issuerSigned.deviceKeyInfo

// Get available namespaces
val namespaces: Set<NameSpace> = issuerSigned.getNameSpaces()

// Get signed items for a namespace
val items: List<IssuerSignedItem<Any>>? = issuerSigned.getIssuerSignedItems("org.iso.18013.5.1")

items?.forEach { item ->
println("Element: ${item.elementIdentifier}")
println("Value: ${item.elementValue}")
}

DeviceSigned Data

Data signed by the holder's device during presentation:

val deviceSigned: DeviceSigned = document?.deviceSigned!!

// Device namespaces (additional device-provided data)
val deviceNameSpaces: DeviceNameSpaces = deviceSigned.nameSpaces

// Device authentication (COSE_Sign1 or COSE_Mac0)
val deviceAuth: DeviceAuth = deviceSigned.deviceAuth

Selective Disclosure

The limitDisclosures method allows filtering which elements to include in a response:

val issuerSigned: IssuerSigned = document.issuerSigned

// Limit disclosures based on the request
val limitedIssuerSigned: IssuerSigned = issuerSigned.limitDisclosures(docRequest)

Common Data Elements

Standard mDL data elements in the org.iso.18013.5.1 namespace:

Element IDTypeDescription
family_namestringFamily name
given_namestringGiven name(s)
birth_datefull-dateDate of birth
issue_datefull-dateDocument issue date
expiry_datefull-dateDocument expiry date
issuing_countrystringISO 3166-1 alpha-2 code
issuing_authoritystringIssuing authority name
document_numberstringLicense number
portraitbytesPhoto of holder (JPEG)
driving_privilegesarrayLicense categories
un_distinguishing_signstringUN country sign
sexintegerISO/IEC 5218 code
heightintegerHeight in cm
weightintegerWeight in kg
eye_colourstringEye color
hair_colourstringHair color
resident_addressstringAddress
age_over_18booleanAge attestation
age_over_21booleanAge attestation
nationalitystringNationality

Response Status Codes

DeviceResponse status codes:

CodeMeaningDescription
0OKRequest processed successfully
10General errorUnspecified error
11CBOR decoding errorInvalid CBOR in request
20User cancelledUser declined to share
val response = deviceResponse

when (response.status?.value?.toInt()) {
0 -> {
// Success - process documents
val documents = response.documents
processDocuments(documents)
}
10 -> {
// General error
handleError("General error from holder")
}
20 -> {
// User cancelled
handleCancellation()
}
else -> {
handleError("Unknown status: ${response.status}")
}
}

Building Requests (Verifier Side)

When building a DeviceRequest as a verifier:

// Build items request for mDL
val itemsRequest = ItemsRequest(
nameSpaces = mapOf(
"org.iso.18013.5.1" to mapOf(
"family_name" to false,
"given_name" to false,
"birth_date" to false,
"portrait" to false,
"age_over_18" to false
)
)
)

// Build doc request
val docRequest = DocRequest(
docType = "org.iso.18013.5.1.mDL",
itemsRequest = itemsRequest,
readerAuth = null // Optional reader authentication
)

// Build device request
val deviceRequest = DeviceRequest(
version = "1.0",
docRequests = listOf(docRequest)
)

Intent to Retain

The intentToRetain boolean in the request indicates whether the verifier intends to store the data element:

  • false - Verifier will not retain the data (e.g., for one-time verification)
  • true - Verifier may store the data (e.g., for records)

Holders may choose to decline sharing elements where intentToRetain is true.