light-mode-image
Learn
MobileGuides

Build a mobile application that can verify an mDoc from an Apple Wallet installed on the same device

Overview

This guide demonstrates how to use the mDocs Verifier Mobile SDK to build a mobile application that can verify an mDoc presented from an Apple Wallet, using the Verify with Wallet API.

The guide covers both the iOS and React Native mDocs Verifier SDKs. Verify with Apple Wallet is an Apple-only API, so there is no Android coverage. Even when you build your verifier app with React Native, the Verify with Apple Wallet flow only runs on iOS. Use the tabs throughout the guide to follow the steps for your chosen SDK.

Prerequisites

Before you get started, let's make sure you have everything you need.

MATTR Resources

As part of your MATTR Pi SDK onboarding process you should have been provided with access to the SDK resources for your chosen platform:

  • ZIP file which includes the required framework: (MobileCredentialVerifierSDK-*version*.xcframework.zip).
  • Sample Verifier app: You can use this app for reference as you work through this guide.

This guide is only meant to be used with the most recent version of the iOS mDocs Verifier SDK.

Verify with Apple Wallet support was added to the React Native mDocs Verifier SDK in v9.0.0 (functional from v9.0.1) and requires iOS 16 or above. Although the app is built with React Native, the Verify with Apple Wallet flow only runs on iOS. Calling it on Android returns a PlatformNotSupported error. This guide is only meant to be used with the most recent version of the React Native mDocs Verifier SDK.

Apple resources

  • Submit an entitlement request to use the Verify with Wallet API. This request would include your app information as well as what information you would like to request for verification and why. You can only proceed with this guide after your request has been approved by Apple.
  • For testing the end-to-end flow, you will need to install the Wallet Identity Developer profile.

Got everything? Let's get going!

Workflow

The following diagram depicts the workflow you will build in this guide:

  1. The user performs an action in a mobile app (Verifier Application) that requires a credential to be presented for verification.
  2. The Verifier Application interacts with the Verify with Wallet API to validate the request can be met using the Apple Wallet. This includes validating:
    • The identity of the verifier.
    • That the verifier is entitled to verify the requested credential type.
    • That the user has a matching credential in their Apple Wallet.
  3. The Verify with Wallet API returns the results of the entitlement validation to the Verifier Application.
  4. If (and only if) all entitlements are valid, the Verifier Application presents a Verify with Apple Wallet button to the user.
  5. The user taps the Verify with Apple Wallet button.
  6. The Verifier Application starts a Verify with Apple Wallet presentation session with the configured MATTR VII tenant.
  7. The MATTR VII tenant calls the Verify with Wallet API with a credentials request.
  8. The Verify with Wallet API invokes the user's Apple Wallet to request the credential.
  9. The Apple Wallet displays a popup interface to the user requesting their consent to share the requested information (they never leave the Verifier Application).
  10. The user provides their consent to sharing a specific credential from the Apple Wallet.
  11. The user's Apple Wallet sends an Apple encrypted credential to the MATTR VII tenant.
  12. The MATTR VII tenant decrypts and verifies the credential.
  13. The MATTR VII tenant sends the verification results to the Verifier Application.
  14. The Verifier Application displays the verification results and the user continues the interaction accordingly.

You will build this workflow in three parts:

  1. Part 1: Setup the MATTR VII Verifier tenant.
  2. Part 2: Configure your Apple Developer account.
  3. Part 3: Build a mobile application.

Part 1: Setup the MATTR VII Verifier tenant

The MATTR VII tenant will be used to interact with your mobile application (generating a verification request) and the wallet application (presenting an mDoc for verification) as per OID4VP and ISO/IEC 18013-7 Annex B. To enable this, you must:

  1. Create a verifier application configuration: Define what applications can create verification sessions with the MATTR VII tenant, and how to handle these requests.
  2. Create a trusted wallet provider configuration: Define how to invoke specific wallet applications as part of a remote verification workflow.
  3. Configure a trusted issuer: The MATTR VII verifier tenant will only accept mDocs issued by these trusted issuers.

Create a verifier application configuration

Each MATTR VII tenant can interact with multiple verifier applications, and can handle requests differently for each application. This means you must create a verifier application configuration that defines how to handle verification requests from your mobile application.

The verifier application Type is always iOS for the Verify with Apple Wallet flow, regardless of the SDK you build with. The credential is always presented through iOS/Apple Wallet, even when your verifier app is built with React Native.

  1. In the navigation panel on the left-hand side, expand the Credential Verification menu.
  2. Select Applications.
  3. Select Create new.
  4. Enter a meaningful Name for your application (e.g. "Verify with Wallet Application").
  5. Use the Type dropdown to select iOS as you are building an iOS application.
  6. Enter your Apple Developer Team ID in the Team ID field. You can find it in the Membership details section of your Apple Developer account.
  7. Enter your iOS application bundle identifier in the Bundle ID field. This is the unique identifier of your iOS application, which you can set in your Xcode project settings. This will be used by the MATTR VII tenant to validate incoming requests are from a known and trusted application.
  8. Select Create.

Make the following request to your MATTR VII tenant to create a verifier application configuration:

Request
POST /v2/presentations/applications
Request body
{
  "name": "Verify with Wallet Application",
  "type": "ios",
  "teamId": "A2B3C4D5E6",
  "bundleId": "io.mattrlabs.dev.sampleApp.MdocSampleApp",
  "resultAvailableInFrontChannel": true
}
  • name : You can use whatever name you'd like, as long as it is unique on your tenant.
  • type : Use ios as you are building an iOS verifier application.
  • teamId : Replace with your Apple Developer Team ID associated with your iOS application. You can find it in the Membership details section of your Apple Developer account.
  • bundleId : Replace with your iOS application bundle identifier. This is the unique identifier of your iOS application, which you can set in your Xcode project settings. This must match the bundle ID you included in your Verify with Apple Wallet entitlement request.
  • resultAvailableInFrontChannel : Setting this to true makes the verification results available directly to the verifier application.

Response

Response body
{
  "id": "0eaa8074-8cc4-41ec-9e42-072d36e2acb0"
  //... rest of application configuration
}
  • id : You will use this value later to initialize the SDK so that requests coming from your verifier application can be recognized and trusted by the MATTR VII tenant.

Configure a trusted issuer

You must configure trusted issuers on your MATTR VII verifier tenant, as presented mDocs will only be verified if they had been issued by a trusted issuer. This is achieved by providing the PEM certificate of the IACA used by these issuers to sign mDocs.

  1. In the navigation panel on the left-hand side, expand the Credential Verification menu.
  2. Click on Trusted issuers.
  3. Click on Create new.
  4. In the Certificate PEM file field, paste the PEM certificate of the IACA used by the issuers you want to trust. For testing purposes, you can use the IACA of the Apple Developer Integrator profile referenced in the prerequisites section.
  5. Click on Add.

Make the following request to your MATTR VII tenant to configure a trusted issuer:

Request
POST /v2/credentials/mobile/trusted-issuers
Request body
{
  "certificatePem": "-----BEGIN CERTIFICATE-----\nMIICYzCCAgmgAwIBAgIKXhjLoCkLWBxREDAKBggqhkjOPQQDAjA4MQswCQYDVQQG\nEwJBVTEpMCcGA1UEAwwgbW9udGNsaWZmLWRtdi5tYXR0cmxhYnMuY29tIElBQ0Ew\nHhcNMjQwMTE4MjMxNDE4WhcNMzQwMTE1MjMxNDE4WjA4MQswCQYDVQQGEwJBVTEp\nMCcGA1UEAwwgbW9udGNsaWZmLWRtdi5tYXR0cmxhYnMuY29tIElBQ0EwWTATBgcq\nhkjOPQIBBggqhkjOPQMBBwNCAASBnqobOh8baMW7mpSZaQMawj6wgM5e5nPd6HXp\ndB8eUVPlCMKribQ7XiiLU96rib/yQLH2k1CUeZmEjxoEi42xo4H6MIH3MBIGA1Ud\nEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRFZwEOI9yq\n232NG+OzNQzFKa/LxDAuBgNVHRIEJzAlhiNodHRwczovL21vbnRjbGlmZi1kbXYu\nbWF0dHJsYWJzLmNvbTCBgQYDVR0fBHoweDB2oHSgcoZwaHR0cHM6Ly9tb250Y2xp\nZmYtZG12LnZpaS5hdTAxLm1hdHRyLmdsb2JhbC92Mi9jcmVkZW50aWFscy9tb2Jp\nbGUvaWFjYXMvMjk0YmExYmMtOTFhMS00MjJmLThhMTctY2IwODU0NWY0ODYwL2Ny\nbDAKBggqhkjOPQQDAgNIADBFAiAlZYQP95lGzVJfCykhcpCzpQ2LWE/AbjTGkcGI\nSNsu7gIhAJfP54a2hXz4YiQN4qJERlORjyL1Ru9M0/dtQppohFm6\n-----END CERTIFICATE-----"
}
  • certificatePem : Replace with the PEM certificate of the IACA used by the issuers you want to trust. For testing purposes, you can use the IACA of the Apple Developer Integrator profile you installed as part of the prerequisites.

Response

A successful 201 response indicates that this issuer's certificate was added to your MATTR VII tenant's trusted issuer's list. This means that mDocs that use this IACA as their root certificate can be trusted and verified.

Create an Apple Identity Access certificate

To enable your MATTR VII tenant to interact with Apple Wallet as part of a remote verification workflow, you must create an Apple Identity Access certificate. This certificate is used to sign requests sent to the Verify with Wallet API.

Currently this action is not available in the MATTR Portal and can only be performed via an API request.

Make the following request to your MATTR VII tenant to create an Apple Identity Access certificate:

Request
POST /v2/presentations/certificates/apple-identity-access-certificates
Request body
{
  "teamId": "A2B3C4D5E6",
  "merchantId": "com.domain.subdomain"
}

Response

A successful 201 response indicates that the Apple Identity Access certificate was created successfully:

Response body
{
  "id": "fd44e792-45ac-11f0-bef8-bb24f133065e",
  "teamId": "A2B3C4D5E6",
  "merchantId": "com.domain.subdomain",
  "csrPem": "string"
}

Make note of the csrPem value, as you will need it in the next part to create a matching Apple Identity Access certificate in your Apple Developer account.

Part 2: Configure your Apple Developer account

Now that you have created the Apple Identity Access certificate in your MATTR VII tenant, you must create a matching certificate in your Apple Developer account and configure it accordingly.

Create an Identity Access Certificate

Log into your Apple Developer account and create a new Apple Pay Identity Access certificate using the CSR you obtained in the previous step. For detailed instructions, see Create an Apple Pay Identity Access certificate.

Once this certificate is created, the Verify With Wallet API will be able to validate requests coming from your MATTR VII tenant, as they are signed using the private key associated with this certificate.

Part 3: Build a mobile application

Now that the MATTR VII verifier tenant and your Apple developer account are both properly configured, you can proceed with the steps required to embed verification capabilities into your mobile verifier application. Use the tabs in each step to follow the instructions for your chosen SDK:

Environment setup

Create a new project

Follow the detailed instructions to Create a new Xcode Project and add your organization's identifier.

Unzip the dependencies file

  1. Unzip the MobileCredentialVerifierSDK-*version*.xcframework.zip file.
  2. Drag the MobileCredentialVerifierSDK-*version*.xcframework folder into your project.
  3. Configure MobileCredentialVerifierSDK.xcframework to Embed & sign.

See Add existing files and folders for detailed instructions.

This should result in the following framework being added to your project:

Framework added

Run the application

Select Run and make sure the application launches with a “Hello, world!” text in the middle of the display, as shown in the following image:

Application ready

Install the SDK

Add the React Native mDocs Verifier SDK to your project:

Install the SDK
yarn add @mattrglobal/mobile-credential-verifier-react-native

Generate the native iOS project

This guide uses Expo with development builds. Generate the native ios/ project so you can add the required capabilities in Xcode:

Generate the native project
yarn expo prebuild

Run the application

Connect a physical iOS device and run the application on it:

Run iOS application
yarn ios --device

Verify with Apple Wallet cannot be tested on an iOS simulator. You must run the application on a physical iOS device (iOS 16 or above) to complete the flow with a wallet installed on the same device.

Configure application entitlement files

To enable your application to interact with the Apple Wallet, you must add the following capabilities to your Xcode project:

  1. Add the In App Identity Presentment capability and define the document types and elements you want to request for verification. You can find a list of supported document types and elements in the Apple Developer documentation.
  2. Add the In App Identity Presentment Merchant IDs and define the merchant IDs you created as part of your Verify with Apple Wallet entitlement request.

You can add these via the Signing & Capabilities tab of your Xcode project. For detailed instructions, see Add capabilities to your app.

Identity Presentment capabilities

Identity Presentment capabilities

Identity Presentment capabilities configuration

Entitlement files configuration

Once yarn expo prebuild has generated the ios/ project, open it in Xcode and add the same capabilities described above via the Signing & Capabilities tab, exactly as in the iOS steps. For detailed instructions, see Add capabilities to your app.

Identity Presentment capabilities

Identity Presentment capabilities

Identity Presentment capabilities configuration

Entitlement files configuration

Re-running yarn expo prebuild --clean regenerates the native ios/ project and may discard manual Xcode changes. Re-apply these capabilities if you regenerate the project.

Initialize the SDK

The first capability you will build into your app is to initialize the SDK so that the app can use its functions and classes.

From v6.0.0, initialize is asynchronous and requires a PlatformConfiguration with both your tenant host and Verifier Application id (this drives SDK Tethering):

Initialize the SDK
let platformConfiguration = PlatformConfiguration(
    tenantHost: URL(string: "https://learn.vii.au01.mattr.global")!, 
    applicationId: "<YOUR_VERIFIER_APPLICATION_ID>"
)
try await mobileCredentialVerifier.initialize(platformConfiguration: platformConfiguration)

Import the SDK and call initialize with a platformConfiguration that sets your tenant host. The function returns a neverthrow Result, so errors are surfaced via result.isErr() rather than a thrown exception:

Initialize the SDK
import { initialize } from "@mattrglobal/mobile-credential-verifier-react-native";

const result = await initialize({
  platformConfiguration: { tenantHost: "https://learn.vii.au01.mattr.global" }, 
});
if (result.isErr()) {
  // handle initialization error
}
  • tenantHost : Replace with the URL of your MATTR VII tenant.

In the React Native SDK, the Verifier Application id is provided later, when you call fetchAppleWalletConfiguration, rather than at initialization.

Validate verification feasibility

Before displaying a Verify with Apple Wallet button, the SDK must confirm that the request can be met using the Apple Wallet. This includes validating:

  • The identity of the verifier (using the provided merchantId).
  • That the verifier is entitled to verify the requested credential type (using the provided docType in the credential request and comparing it against the entitlements associated with this merchantId).
  • That the user has a credential that matches the requested docType in their Apple Wallet.

This is achieved by calling the fetchAppleWalletConfiguration method and providing a MobileCredentialRequest (and a merchantId). The request defines what information is requested for verification and is used by the Verify with Wallet API to determine whether the requested credential type is supported by the entitlements associated with your application. The merchantId is the merchant ID you created as part of your Verify with Apple Wallet entitlement request, and is used to determine whether this specific merchant is authorized to request the specified credential type.

The MobileCredentialRequest defines what information is required for verification:

  • The requested credential type (e.g. org.iso.18013.5.1.mDL).
  • The claims required for verification (e.g. family_name).
  • The requested namespace (e.g. org.iso.18013.5.1).
  • Whether or not the verifier intends to persist the claim value (true/false).

Call the fetchAppleWalletConfiguration method:

Fetch Apple Wallet configuration
func fetchAppleWalletConfiguration(
    request: MobileCredentialRequest,
    merchantId: String
) async -> Result<AppleWallet, MobileCredentialVerifierError>

If all checks pass, this method returns an instance of the AppleWallet class, which includes the UI elements and methods required to request a credential from an Apple Wallet.

Your application can then present one of the returned UI elements (for example a Verify with Apple Wallet button) to the user, which when tapped would invoke the Apple Wallet to request the credential for verification.

Verify with Apple Wallet button

MobileCredentialRequest example

Swift
    let mobileCredentialRequest = MobileCredentialRequest(
        docType: "org.iso.18013.5.1.mDL",
        namespaces: [
            "org.iso.18013.5.1":  [
                "family_name": false,
                "given_name": false,
                "birth_date": false
            ]
        ]
    )

Call fetchAppleWalletConfiguration with the request, your verifier applicationId, and the merchantId. It returns a Result<AppleWallet, FetchAppleWalletConfigurationError>:

Fetch Apple Wallet configuration
import { fetchAppleWalletConfiguration } from "@mattrglobal/mobile-credential-verifier-react-native";

const result = await fetchAppleWalletConfiguration({
  request: mobileCredentialRequest,
  applicationId: "<your-verifier-application-id>",
  merchantId: "merchant.com.example.app",
});
if (result.isErr()) {
  // request cannot be met via Apple Wallet, do not show the button
  return;
}
const appleWallet = result.value;

Unlike the iOS SDK, the React Native AppleWallet type exposes only a requestMobileCredentials method. It does not return an SDK-rendered button or any UI elements. Your app renders its own Verify with Apple Wallet button, enabling it only after fetchAppleWalletConfiguration succeeds.

MobileCredentialRequest example

React Native
const mobileCredentialRequest = {
  docType: "org.iso.18013.5.1.mDL",
  namespaces: {
    "org.iso.18013.5.1": {
      family_name: false,
      given_name: false,
      birth_date: false,
    },
  },
};

Request a credential from an Apple Wallet

Once the user taps the Verify with Apple Wallet button, you can call the requestMobileCredentials method on the AppleWallet instance to invoke the Apple Wallet and request the mDoc for verification.

  • challenge : Unique value that must be generated by the verifier app. Should be a unique, unpredictable value generated for each verification session to mitigate replay attacks by ensuring the response from the Apple Wallet is tied to the current request and cannot be reused maliciously. Always generate a new challenge for every credential request.

Once called, this method orchestrates the interaction to request the mDoc for verification from the Apple Wallet. The user sees the Apple Wallet popup interface, where they can select the credential to present for verification and provide their consent to share the requested information.

Call the requestMobileCredentials method:

Request a credential from Apple Wallet
func requestMobileCredentials(challenge: String) async throws -> OnlinePresentationSessionResult

Call requestMobileCredentials on the appleWallet instance returned by fetchAppleWalletConfiguration. It returns a Result<OnlinePresentationSessionResult, RequestMobileCredentialsWithAppleWalletError>:

Request a credential from Apple Wallet
const result = await appleWallet.requestMobileCredentials(challenge);
if (result.isErr()) {
  // handle error
  return;
}
const sessionResult = result.value;

Display verification results and continue the interaction

After the user consents, Apple Wallet sends the encrypted credential to the MATTR VII tenant. The tenant decrypts and verifies it, then returns the verification results to your app as an OnlinePresentationSessionResult.

The results are returned as an OnlinePresentationSessionResult. Your app should then:

  • Validate the challenge in the OnlinePresentationSessionResult matches the one you sent in the request.
  • Parse the OnlinePresentationSessionResult object to extract the verification results.
  • Display the results to the user and continue the interaction accordingly.

After checking result.isErr() on the value returned by requestMobileCredentials, read the OnlinePresentationSessionResult from result.value (the sessionResult in the previous step). Your app should then:

  • Validate the challenge in the sessionResult matches the one you sent in the request.
  • Parse the sessionResult object to extract the verification results.
  • Display the results to the user and continue the interaction accordingly.

How would you rate this page?

Last updated on

On this page