Mobile Credentials (mDoc) Overview
The IDK implements ISO/IEC 18013-5 for mobile driving licenses (mDL) and mobile credentials (mDoc). This standard defines how to store, present, and verify identity credentials on mobile devices using secure, privacy-preserving protocols.
What is mDoc?
An mDoc (mobile document) is a digital credential stored on a mobile device that can be presented to verifiers through close-range communication technologies like NFC and Bluetooth. The ISO 18013-5 standard was originally designed for mobile driving licenses but has been adopted for other credential types.
Key characteristics of mDoc:
- Offline verification: Credentials can be verified without an internet connection
- Selective disclosure: Holders can share only specific attributes, not the entire credential
- Cryptographic security: Issuer signatures and device authentication prevent tampering
- Privacy preserving: Reader authentication ensures credentials are only shared with legitimate verifiers
Protocol Flow
The mDoc presentation protocol consists of two main phases:
Phase 1: Engagement
During engagement, the holder and verifier establish how they will communicate. The holder's device generates engagement data containing:
- A device engagement structure with transport options
- An ephemeral public key for establishing the session
This engagement data is transmitted out-of-band through:
- QR code: The holder displays a QR code that the verifier scans
- NFC tap: The holder taps their device on the verifier's reader
- TO_APP (mdoc://): App-to-app reverse engagement for ISO 18013-7
Phase 2: Data Transfer
Once engaged, the actual credential exchange occurs:
- Reader request: The verifier sends a
DeviceRequestspecifying which data elements are needed - User consent: The holder reviews the request and approves sharing
- Device response: The holder's device creates a signed
DeviceResponsewith the requested data - Verification: The verifier validates signatures and trust chains
IDK Components
The IDK provides several components for implementing mDoc functionality:
MdocEngagementManager
The central entry point for mDoc operations. It manages the complete lifecycle from engagement through data transfer.
- Android/Kotlin
- iOS/Swift
val engagementManager = session.component.mdocEngagementManager
// Access engagement instances
val qrEngagement = engagementManager.qrEngagement // StateFlow<EngagementInstance?>
val nfcEngagement = engagementManager.nfcEngagement // StateFlow<EngagementInstance?>
val toAppEngagement = engagementManager.toAppEngagement // StateFlow<EngagementInstance?>
// Access event hub for UI integration
val eventHub = engagementManager.eventHub
let engagementManager = session.component.mdocEngagementManager
// Access engagement instances
let qrEngagement = engagementManager.qrEngagement // StateFlow<EngagementInstance?>
let nfcEngagement = engagementManager.nfcEngagement // StateFlow<EngagementInstance?>
let toAppEngagement = engagementManager.toAppEngagement // StateFlow<EngagementInstance?>
// Access event hub for UI integration
let eventHub = engagementManager.eventHub
See the Engagement Manager guide for details.
TransferManager
Handles the data transfer phase after engagement is established. Manages device requests and responses.
- Android/Kotlin
- iOS/Swift
// Start engagement to get transfer manager
val transferManager = engagementInstance.start()
// Receive and respond to requests
val deviceRequest = transferManager.receiveDeviceRequest()
val deviceResponse = transferManager.createResponse(deviceRequest, documentProvider)
transferManager.sendDeviceResponse(deviceResponse)
// Start engagement to get transfer manager
let transferManager = try await engagementInstance.start()
// Receive and respond to requests
let deviceRequest = try await transferManager.receiveDeviceRequest()
let deviceResponse = try await transferManager.createResponse(
deviceRequest: deviceRequest,
documentProvider: documentProvider
)
try await transferManager.sendDeviceResponse(deviceResponse: deviceResponse)
See the Transfer Manager guide for details.
Transport Layer
The IDK supports multiple transports for the data transfer phase:
| Transport | Use Case |
|---|---|
| BLE (Bluetooth Low Energy) | Common for mobile-to-mobile presentation |
| NFC | Quick tap-and-go scenarios |
| REST API / Website | Remote or server-based verification |
| OID4VP | Integration with OpenID4VP presentation flows |
| WiFi Aware | Direct device-to-device WiFi connections |
See the Transports guides for configuration details.
Engagement Types
The IDK supports three engagement types:
| Type | Standard | URI Scheme | Description |
|---|---|---|---|
| QR | ISO 18013-5 | mdoc: (opaque) | QR code displayed by holder |
| NFC | ISO 18013-5 | N/A | NFC tap proximity engagement |
| TO_APP | ISO 18013-7 | mdoc:// or mdoc-openid4vp:// | App-to-app reverse engagement |
URI Scheme Patterns
The toApp() method supports three URI patterns:
mdoc:(opaque, no slashes): Classic reverse engagement with BLE/NFCmdoc://(hierarchical, with slashes): REST API / Website retrievalmdoc-openid4vp://: OID4VP with OAuth 2.0 integration
Credential Structure
An mDoc credential consists of:
IssuerSigned Data
Data signed by the credential issuer:
- Mobile Security Object (MSO): Contains digests of all data elements, signed by the issuer
- Namespaces: Data elements organized by namespace (e.g.,
org.iso.18013.5.1for mDL) - Issuer certificate chain: X.509 certificates establishing trust
- Android/Kotlin
- iOS/Swift
// IssuerSigned structure
data class IssuerSigned(
val nameSpaces: IssuerSignedNameSpaces?,
val issuerAuth: COSE_Sign1<MobileSecurityObject>
) {
val MSO: MobileSecurityObject // Mobile Security Object
val deviceKeyInfo: DeviceKeyInfoCbor // Device key from MSO
fun getNameSpaces(): Set<NameSpace>
fun getIssuerSignedItems(ns: String): List<IssuerSignedItem<Any>>?
fun limitDisclosures(docRequest: DocRequest): IssuerSigned
}
// IssuerSigned structure
struct IssuerSigned {
let nameSpaces: IssuerSignedNameSpaces?
let issuerAuth: COSE_Sign1<MobileSecurityObject>
var MSO: MobileSecurityObject // Mobile Security Object
var deviceKeyInfo: DeviceKeyInfoCbor // Device key from MSO
func getNameSpaces() -> Set<NameSpace>
func getIssuerSignedItems(ns: String) -> [IssuerSignedItem]?
func limitDisclosures(docRequest: DocRequest) -> IssuerSigned
}
DeviceSigned Data
Data signed by the holder's device during presentation:
- Session transcript: Cryptographic binding to the current session
- Device authentication: Proves the holder controls the device key
- Android/Kotlin
- iOS/Swift
// DeviceSigned structure
data class DeviceSigned(
val nameSpaces: DeviceNameSpaces,
val deviceAuth: DeviceAuth
)
// DeviceSigned structure
struct DeviceSigned {
let nameSpaces: DeviceNameSpaces
let deviceAuth: DeviceAuth
}
Data Elements
Data elements are individual attributes within a credential. For an mDL, typical elements include:
| Element | Namespace | Description |
|---|---|---|
family_name | org.iso.18013.5.1 | Holder's family name |
given_name | org.iso.18013.5.1 | Holder's given name |
birth_date | org.iso.18013.5.1 | Date of birth |
portrait | org.iso.18013.5.1 | Photo of the holder |
document_number | org.iso.18013.5.1 | License number |
driving_privileges | org.iso.18013.5.1 | License categories |
issue_date | org.iso.18013.5.1 | When the license was issued |
expiry_date | org.iso.18013.5.1 | When the license expires |
age_over_18 | org.iso.18013.5.1 | Age attestation claim |
age_over_21 | org.iso.18013.5.1 | Age attestation claim |
Security Model
mDoc security relies on several layers:
Issuer Trust
The credential issuer signs the MSO with their private key. Verifiers validate this signature against a trust anchor (typically a certificate from a trusted authority).
Device Binding
The credential is bound to a specific device through a device key. During issuance, the device generates a key pair and the public key is included in the MSO. During presentation, the device proves possession of the private key.
Session Encryption
All communication after engagement is encrypted using keys derived from the ephemeral key exchange. This prevents eavesdropping and man-in-the-middle attacks.
Reader Authentication
Optionally, holders can require verifiers to prove their identity before sharing data. This prevents credential harvesting by unauthorized parties.
Getting Started
To implement mDoc functionality in your application:
- Set up the Engagement Manager for holder or verifier roles
- Configure appropriate transports for your use case
- Handle events to build responsive UIs
- Implement the data transfer flow for actual credential exchange