Proximity (in-person) presentation

The SDK enables presenting a claimed mDoc for verification via a proximity presentation workflow as per ISO 18013-5.

To build a step-by-step implementation of this workflow, give the Proximity presentation tutorial a try.

Sequence diagram

Detailed steps

Display a QR code with an embedded device engagement String

The ISO/IEC 18130-5:2021 standard defines that a proximity presentation workflow is always initiated by the holder (wallet user), who must create a QR code for the verifier to scan in order to initiate the device engagement phase.

Thus, your wallet application must provide a UI element for the user to interact with in order to trigger device engagement with the verification device by calling the SDK’s createProximityPresentationSession method:

createProximityPresentationSession method
func createProximityPresentationSession(
    onRequestReceived requestReceivedAction: @escaping ([(request: MobileCredentialRequest, matchedMobileCredentials: [MobileCredentialMetadata])]?, ProximityPresentationSessionError?) -> Void,
    onConnected onConnectedAction: (() -> Void)? = nil,
    onSessionTerminated sessionTerminatedAction: ((ProximityPresentationSessionTerminationError?) -> Void)? = nil,
    mobileCredentialAuthenticationOption: MobileCredentialAuthenticationOption = .signature,
    bleMode: BLEMode = .mDocClientCentral
) async throws -> ProximityPresentationSession
  • mobileCredentialAuthenticationOption : Device authentication options for credentials presented in the current session:
    • signature (default): Authenticates the credential based on its digital signature.
    • mac : Authenticates the credential by computing the device Message Authentication Code (MAC).
  • bleMode : BLE mode to use for data transfer:
    • mDocClientCentral (default): The holder acts as a client and the verifier acts as a server.
    • mDocPeripheralServer : The holder acts as a server and the verifier acts as a client.

This method returns a ProximityPresentationSession instance, which includes a deviceEngagement string in Base64 format. This string contains the information required to establish a secure connection, including:

  • Wireless communication protocols supported by the holder.
  • How the verifier can connect with the holder.
  • Ephemeral public key which is unique to the current session.
  • Additional feature negotiations.

Your wallet application will need to convert this string into a QR code and display it for the verifier device to scan. You can see an example implementation in the Proximity presentation tutorial.

UX Considerations and best practices

This method requires granting bluetooth permissions to your wallet application. To enable this, you must add the NSBluetoothAlwaysUsageDescription attribute to the application’s info.plist file.

When calling this method for the first time, a system UI will prompt the user to grant bluetooth permissions to the application. If the user has denied access, the MobileCredentialHolderError.bluetoothPermissionDenied error is thrown and the workflow cannot continue until bluetooth permissions are granted to the application. Your wallet application should provide a UX to cover this scenario.

Handle the verification request

After the SDK’s createProximityPresentationSession method is called it enters a listening state and can handle three types of events:

  • onConnected: When a secure connection is established with the verifier application. This can be used by your wallet application to provide a successful connection indication to the user.
  • onSessionTerminated: When a secure connection is terminated for whatever reason. This can be used by your wallet application to indicate a terminated connection and advice how to proceed.
  • onRequestReceived: When a presentation request is received from the verifier. This event should be used by your wallet application to display the verification request to the user.

When the SDK receives a verification request from the connected verifier (onRequestReceived event), the createProximityPresentationSession method returns an array that includes pairs of requested and matching credentials:

Requested and matching credentials
[(request: MobileCredentialRequest, matchedMobileCredentials: [MobileCredentialMetadata])]

Your wallet application can now parse these structures and display to the user:

  • What information is requested for verification.
  • What existing credentials match the requested information.
  • What claims from these existing credentials will be shared with the verifier.

Then, your wallet application should include a UI element for the user to consent sharing the information with the verifier:

Provide user consent

UX Considerations and best practices

The MATTR GO example app splits this information into two screens:

  • The first screen displays what information is requested for verification.
  • Once the users choose to continue, a second screen is displayed with the matching credentials and a consent button.

You can choose to follow a similar approach or combine all information into a single view, depending on your UX/UI preferences.

Whatever approach you choose, consider creating a single view that is used for both the proximity and online presentation flows for a more consistent UX.

request and matchedMobileCredentials structure

The array returned by the createProximityPresentationSession method when a verification request is received from the verifier (onRequestReceived event) includes the following structures:

  • request : This is a MobileCredentialRequest structure that defines the information requested for verification:

    MobileCredentialRequest structure
    var docType: MobileCredentialDataTypes.DocType
    let namespaces: [MobileCredentialDataTypes.NameSpace : [MobileCredentialDataTypes.ElementID : MobileCredentialDataTypes.IntentToRetain]]
    • docType : Indicates the requested credential type.
    • namespaces : This is a dictionary of namespaces that are requested for verification. Each namespace is itself a dictionary of:
      • ElementID : Requested claim identifier.
      • IntentToRetain : Boolean indicating whether or not the relying party will retain this claim’s value after the verification process is completed.
  • matchedMobileCredentials : This is a MobileCredentialMetadata structure that includes the metadata of stored credentials that include the information included in the corresponding MobileCredentialRequest:

    matchedMobileCredentials structure
    let branding: Branding?
    let claims: [MobileCredentialDataTypes.NameSpace : [MobileCredentialDataTypes.ElementID]]?
    let docType: String
    let id: String
    let issuerInfo: IssuerInfo
    let validityInfo: Validity
    • branding : Information and links to graphic assets that should be used by your wallet application to render this credential.
    • claims : This is a dictionary of namespaces that are included in the credential and the identifiers (ElementID) of claims that are requested for verification from this credential.
    • doctype : Credential’s type.
    • id : Unique identifier of this credential.
    • issuerInfo :
      • commonName : Issuer’s common name, matching its certificate. This can be used to display the credential issuer’s human readable name to the user.
      • trustedIssuerCertificateId : Issuer’s IACA certificate.
    • validityInfo :
      • validFrom : Indicates the date when this credential becomes valid.
      • validUntil : Indicates the date when this credential expires.

    The MobileCredentialMetadata structure does not include any of the credential claims or verification status. If you want to display this information to the user as part of the verification workflow, use the getCredential method with the credential’s id to retrieve this information as an instance of MobileCredential. You can than parse this structure and display any required information to the user.

Send presentation response

When the user consents to sharing the displayed information with the verifier, your wallet application must call the SDK’s sendResponse method to share the selected credentials with the verifier:

sendResponse method
func sendResponse(credentialIds: [String], terminateSession: Bool = false) async throws
  • credentialIds : Use this array to include the identifiers of all credentials that should be included in the response to the verifier.
  • autoRedirect : Controls the application behavior after a response is sent:
    • When set to true, the session is terminated as soon as a response is sent.
    • When set to false, your application can manually terminate the session when appropriate.

UX Considerations and best practices

  • For large credentials, it is recommended to set autoRedirect to false to ensure the entire credential was received by the verifier before terminating the session.
  • Some verification requests might include more than one credential. Furthermore, the user might have more than one credential that matches the verification request. Your wallet application should therefore offer a UI to enable the user to select what credential(s) to share in the response.

Continue the interaction with the verifier

Once the response is sent by your wallet application, it can be verified by the verifier application, and the in-person interaction can continue based on the verification results.