The structure for verifying an mDL is very similar to implementing the presentation of an mDL. To verify an mDL over BLE you will need to manage the BLEReaderSessionState and provide a UI for every state during the presentation process.
1. Scanning Documents
Rather than generating a QR-code, for a verifier, you will have to implement a scanning ability. For mdoc verification, you can directly use the QRCodeScanner. If you want to implement a generic scanner that can handle PDF417 VC Barcodes and Machine Readable Zones, check out this example of a Scanning Component.
Verify mdocs
Here, we give an example of what your VerifyMdocView could look like. You can also directly reference our example implementation.
import SpruceIDMobileSdk
// An Example View for Verification of Mdocs
public struct VerifyMDocView: View {
@Binding var path: NavigationPath
@State private var scanned: String?
public var body: some View {
if scanned == nil {
QRCodeScanner(
title: "Scan QR Code",
subtitle: "Looking...",
onRead: { code in
self.scanned = code
},
onCancel: onCancel,
titleFont: .customFont(font: .inter, style: .bold, size: .h0),
subtitleFont: .customFont(font: .inter, style: .bold, size: .h4),
cancelButtonFont: .customFont(font: .inter, style: .medium, size: .h3),
readerColor: .white
)
} else {
// Define an MdocReaderView and initiate it when the code is scanned
MDocReaderView(
// Set the scanned value
uri: scanned!,
// Define the items you want to query by namespace, attribute_name
// and intent to retain:
requestedItems: ["org.iso.18013.5.1": ["given_name": true]],
// Enter an array of issuer certificates that you accept (e.g. a list of US states).
// These issuer certificates should follow the IACA profile as defined in ISO/IEC 18013-5 Annex B.
trustAnchorRegistry: [<issuer_cert>],
onCancel: onCancel,
path: $path
)
}
}
func onCancel() {
// Define what to do when a user cancels the scan
self.scanned = nil
path.removeLast()
}
}
MdocReaderView
Build the Delegate that holds the BLEReaderSessionState and the mDocReader sessionManager.
// Build out your Reader Delegate
class MDocReaderDelegate: ObservableObject {
@Published var state: BLEReaderSessionState = .advertizing
private var mdocReader: MDocReader?
init(
uri: String,
requestedItems: [String: [String: Bool]],
trustAnchorRegistry: [String]?
) {
// MdocReader is a core SpruceKit Component.
self.mdocReader = MDocReader(
callback: self,
uri: uri,
requestedItems: requestedItems,
trustAnchorRegistry: trustAnchorRegistry
)
}
func cancel() {
self.mdocReader?.cancel()
}
}
// Make sure to extend the BLEReaderSessionStateDelegate to MdocReaderDelegate
extension MDocReaderDelegate: BLEReaderSessionStateDelegate {
public func update(state: BLEReaderSessionState) {
self.state = state
}
}
Once you have your Delegate implemented, you can add it to your MdocReaderView, which manages the UI based on the SessionState.
// Build your MdocReaderView
public struct MDocReaderView: View {
@StateObject var delegate: MDocScanViewDelegate
@Binding var path: NavigationPath
var onCancel: () -> Void
init(
uri: String,
requestedItems: [String: [String: Bool]],
trustAnchorRegistry: [String]?,
onCancel: @escaping () -> Void,
path: Binding<NavigationPath>
) {
self._delegate = StateObject(
wrappedValue: MDocReaderDelegate(
uri: uri,
requestedItems: requestedItems,
trustAnchorRegistry: trustAnchorRegistry
)
)
self.onCancel = onCancel
self._path = path
}
@ViewBuilder
var cancelButton: some View {
Button("Cancel") {
self.cancel()
}
.padding(10)
.buttonStyle(.bordered)
.tint(.red)
public var body: some View {
VStack {
switch self.delegate.state {
// Manage the BLE ReaderSessionStates here
}
}
.padding(.all, 30)
.navigationBarBackButtonHidden(true)
}
func cancel() {
self.delegate.cancel()
self.onCancel()
}
}
There you have it, you now have everything you need for an mDL verification flow. You can:
Initiate a QR Code Scanner
Manage the states of the BleReaderSession with appropriate UI of your design