Frequently Asked Questions
General
What platforms does the IDK support?
The IDK is a Kotlin Multiplatform (KMP) library supporting:
- Android (API 26+)
- iOS (iOS 14+, via Swift/Objective-C interop)
- JVM (Java 11+)
- JavaScript/WASM (Browser and Node.js)
What credential formats are supported?
The IDK supports multiple credential formats:
- mDoc (ISO 18013-5): Mobile driving licenses and other ISO-standard credentials
- SD-JWT VC: Selective Disclosure JWT Verifiable Credentials
- W3C Verifiable Credentials: JSON-LD and JWT formats
What protocols does the IDK implement?
Key protocols include:
- OpenID for Verifiable Presentations (OID4VP): For credential presentation
- OpenID for Verifiable Credential Issuance (OID4VCI): For credential issuance
- OAuth 2.0: Authorization framework with PKCE and DPoP extensions
- ISO 18013-5: Device engagement and data transfer for mDoc
Installation
How do I add the IDK to my project?
For Android/Kotlin projects, add the dependencies to your build.gradle.kts:
dependencies {
implementation("com.sphereon.idk:core:0.13.0")
implementation("com.sphereon.idk:mdoc:0.13.0")
// Add other modules as needed
}
For iOS projects, use Swift Package Manager with the repository URL.
What are the minimum requirements?
- Android: API level 26 (Android 8.0) or higher
- iOS: iOS 14.0 or higher
- JVM: Java 11 or higher
- Gradle: 8.0 or higher (for Android/JVM projects)
How do I configure ProGuard/R8?
The IDK includes consumer ProGuard rules. No additional configuration is typically needed. If you encounter issues, ensure serialization classes are kept:
-keep class com.sphereon.idk.** { *; }
-keepclassmembers class * {
@kotlinx.serialization.Serializable *;
}
mDoc / ISO 18013-5
How do I present an mDoc credential?
Use the MdocEngagementManager to create an engagement and handle the presentation flow:
val engagement = engagementManager.createEngagement {
engagement {
qr { enabled = true }
}
retrieval {
ble { centralClientMode = true }
}
}
// Display QR code and wait for verifier connection
val qrData = engagement.deviceEngagement.toQrCode()
What transports are supported for mDoc?
The IDK supports:
- BLE (Bluetooth Low Energy): Proximity-based transfer
- NFC: Tap-to-share transfer
- HTTP/WebSocket: Remote transfer for online verification
How do I validate an mDoc issuer?
Use the certificate validator with IACA trust anchors:
val result = certificateValidator.validateMdocChain(
mso = mobileSecurityObject,
iacaTrustAnchors = loadIacaCertificates()
)
OAuth 2.0 / OpenID
How do I implement PKCE?
PKCE is enabled by default. The client automatically generates code verifiers and challenges:
val authRequest = oauth2Client.buildAuthorizationRequest {
clientId = "my-client"
redirectUri = "myapp://callback"
usePkce = true // Default
}
// Exchange code with the verifier
val tokens = oauth2Client.exchangeCode(
code = authorizationCode,
codeVerifier = authRequest.codeVerifier
)
How do I use DPoP for sender-constrained tokens?
Generate a DPoP key and include it in token requests:
val dpopKey = keyManager.generateKeyAsync(alg = SignatureAlgorithm.ES256)
val tokens = oauth2Client.exchangeCodeWithDpop(
code = authorizationCode,
dpopKey = dpopKey,
tokenEndpoint = "https://auth.example.com/token"
)
Key Management
How are keys stored securely?
The IDK uses platform-appropriate secure storage:
- Android: Android Keystore for hardware-backed keys
- iOS: Secure Enclave and Keychain
- JVM: Software-based storage with optional HSM integration
Can I use cloud KMS providers?
Yes, the IDK supports pluggable KMS providers:
- AWS KMS
- Azure Key Vault
- Google Cloud KMS
- Custom providers via the
KeyManagerServiceinterface
How do I migrate keys between devices?
Keys stored in hardware security modules cannot be exported. For device migration:
- Use the credential backup/restore functionality if supported by your credentials
- Re-issue credentials on the new device
- Use cloud-synced software keys for less sensitive operations
Trust Validation
How do I validate ETSI trust lists?
Load and configure trust lists:
val trustValidator = TrustValidator {
etsiTrustLists {
lotlUrl = "https://ec.europa.eu/tools/lotl/eu-lotl.xml"
minimumStatus = TrustServiceStatus.QUALIFIED
}
}
val result = trustValidator.validateTrust(certificate, TrustPurpose.CREDENTIAL_ISSUER)
How often should trust lists be refreshed?
Trust lists should be refreshed every 12-24 hours. Enable background refresh:
etsiTrustLists {
cacheEnabled = true
backgroundRefresh = true
cacheDuration = Duration.ofHours(24)
}
Multi-Tenancy
How do I implement multi-tenant isolation?
Use the scoping system to isolate tenant data:
// Create tenant-scoped context
val tenantContext = session.createTenantContext(tenantId)
// All components accessed through this context are tenant-isolated
val tenantKeyManager = tenantContext.component.keyManagerService
Can different tenants use different configurations?
Yes, use the ConfigProvider to supply tenant-specific configuration:
val config = ConfigProvider {
tenant(tenantId) {
property("oauth2.client-id", tenantClientId)
property("oauth2.issuer", tenantIssuer)
}
}
Performance
How can I optimize credential verification?
- Cache trust lists and revocation data
- Use parallel validation for multiple credentials
- Pre-load issuer certificates at app startup
- Use BLE central-client mode for faster mDoc transfers
What are typical latency expectations?
- mDoc BLE transfer: 2-5 seconds for typical credentials
- mDoc NFC transfer: 1-3 seconds for typical credentials
- SD-JWT verification: Less than 100ms for signature validation
- OCSP check: 100-500ms (depends on responder)
Troubleshooting
Why is BLE transfer failing on Android?
Common causes:
- Missing Bluetooth permissions in manifest
- Location permissions not granted (required for BLE scanning)
- BLE advertising not supported on device
- Conflicting UUID with other apps
Why is NFC not working on iOS?
Check:
- NFC entitlements are configured in your app
NFCReaderUsageDescriptionis set in Info.plist- Device supports NFC (iPhone 7 and later)
- App is in foreground when scanning
How do I debug certificate validation failures?
Enable detailed logging:
certificateValidator.validate(
certificate = cert,
trustAnchors = anchors,
options = ValidationOptions(
debugLogging = true
)
)
Check for common issues:
- Certificate chain incomplete
- Time synchronization issues
- Revocation check failures
- Missing trust anchors
Getting Help
For additional support:
- Check the GitHub repository for known issues
- Review the API documentation for detailed method signatures
- Contact support for enterprise licensing questions