GuidesCredential verificationProximity verification

How to build mDocs proximity verification capabilities into my iOS application

This guide offers step-by-step instructions for using the iOS mDocs verifier SDK to build the capability to verify an mDoc presented via a proximity presentation workflow as per ISO/IEC 18013-5.

If you are unfamiliar with this presentation workflow, the corresponding tutorial might be a better starting point as it offers more context and a high level overview of the user experience.

Prerequisites

  • Access to the SDK’s GitHub distribution repository. Refer to the getting started guide for more information.

Access requires an SSH key associated with the GitHub user who has access to the distribution repo. Please contact us if you are having trouble with setting this up.

Overview

This guide comprises the following steps:

  1. Setup your project.
  2. Initialise the SDK.
  3. Manage certificates.
  4. Verify an mDoc.

Setup your project

  1. Install the SDK.
  2. Add Bluetooth permissions to your application.

Initialise the SDK

  1. Create a new variable:
Creating a new variable
    var mobileCredentialVerifier: MobileCredentialVerifier
  1. Initialise the SDK by creating a new instance of the MobileCredentialVerifier class and calling its initialise function:
Initialising the SDK
    mobileCredentialVerifier = MobileCredentialVerifier.shared
    try mobileCredentialVerifier.initialise()

Manage certificates

  1. Create a new view for managing issuer certificates.
  2. Create a UI element that calls the addTrustedIssuerCertificates function and enables the user to add a new certificate:
Adding a new certificate
 
viewModel.addCertificate(certificateString)
 
...
 
func addCertificate(_ certificate: String) {
    Task {
        do {
            _ = try await mobileCredentialVerifier.addTrustedIssuerCertificates(certificates: [certificate])
            self.getCertificates()
        }
        catch {
            print(error.localizedDescription)
        }
    }
}
  1. Create a UI element that displays existing certificates by calling the getTrustedIssuerCertificates function:
Displaying existing certificates
viewModel.getCertificates()
 
...
 
func getCertificates() {
    do {
        let fetchedCertificates = try mobileCredentialVerifier.getTrustedIssuerCertificates()
        // Updating the UI from the main thread
        DispatchQueue.main.async {
            self.certificates = fetchedCertificates
        }
    } catch {
        print(error.localizedDescription)
    }
}
  1. Create a UI element that enables the user to remove an existing certificate by calling the deleteTrustedIssuerCertificate function:
Removing an existing certificate
    .swipeActions(edge: .trailing) {
Button(role:. destructive) {
    viewModel.removeCertificate(certificate.id)
} label: {
    Image(systemName: "trash")
}
 
...
 
    func removeCertificate(_ certificateID: String) {
        do {
            try mobileCredentialVerifier.deleteTrustedIssuerCertificate(certificateId: certificateID)
            // Refresh the certificates list after deletion
            self.getCertificates()
        } catch {
            print(error.localizedDescription)
        }
    }
}
 

Verify an mDoc

  1. Create a new presentation request to define the information you wish to verify:
Creating a presentation request
    let mobileCredentialRequest = MobileCredentialRequest(
        docType: "org.iso.18013.5.1.mDL",
        namespaces: [
            "org.iso.18013.5.1.mDL":  [
                "family_name": false,
                "first_name": false,
                "birth_date": false
            ]
        ]
    )

Based on your implementation, this request can be created in different ways:

  • You can hardcode it into the application.
  • You can create a number of different requests and create a UI element to let the user choose between them.
  • You can create a UI element that lets the user create a custom request on their own.
  1. Create a variable to store the response from the wallet application:
Creating a variable to store the wallet response
@Published var receivedDocuments: [MobileCredentialPresentation] = []
  1. Integrate a QR scanning capability into your app. Refer to our tutorial for an example using CodeScanner.

This capability should enable your app to scan a QR code presented by a wallet application and extract the deviceEngagement string from it to initiate the proximity presentation session.

  1. Call the createProximityPresentationSession function with the String obtained from the QR code to:
    1. Establish a secure connection with the wallet application device.
    2. Send a presentation request by calling the requestMobileCredentials function with an array of MobileCredentialRequests which includes the relevant presentation requests:
Creating a proximity presentation session and sending a presentation request
    func setupProximityPresentationSession(_ string: String) {
        Task {
            do {
                let _ = try await mobileCredentialVerifier.createProximityPresentationSession(
                    encodedDeviceEngagementString: string,
                    onSessionTerminated: { _ in print("Session Terminated") }
                )
                sendDeviceRequest()
            } catch {
                print(error.localizedDescription)
            }
        }
    }
 
...
 
    func sendDeviceRequest() {
     Task { @MainActor in
         do {
 
             // Refresh the list of received documents
             if !receivedDocuments.isEmpty {
                 receivedDocuments = []
             }
 
             // Find the existing proximity presentation session.
             let presentationSession = try? mobileCredentialVerifier.getCurrentProximityPresentationSession()
 
             // Request mDocs
             let deviceResponse = try await presentationSession?.requestMobileCredentials(
                 request: [mobileCredentialRequest]
             )
 
             // Assign new values from the response
             receivedDocuments = deviceResponse?.credentials ?? []
             // Terminate session after response is received (optional)
             await presentationSession?.terminateSession()
         } catch {
             print(error)
             receivedDocuments = []
         }
     }
 }

The requestMobileCredentials function returns an instance of MobileCredentialResponse which can be stored in a variable.

  1. Create a new view for using the MobileCredentialResponse instance to display verification results to the verifier app user.