How to setup mDocs online verification

mDocs are digital credentials based on the ISO/IEC 18013-5 standard and DTS 18013-7 technical specification, designed to be stored on a holder’s mobile device and support both in-person or remote (online) verification workflows.

The purpose of this guide is to explain how to configure an end-to-end online verification workflow of mDocs. This can include different sets of capabilities:

  • Adding online verification capabilities to a web application.
  • Adding online presentation capabilities to a digital wallet application.

Prerequisites

Overview

The configuration process includes the following steps:

  1. Configure the MATTR VII Verifier tenant.
  2. Add online presentation capabilities into a web application.
  3. Integrate a backend into the verification workflow (optional).
  4. Add online verification capabilities into a wallet application.

Configure the MATTR VII Verifier tenant

This step is only required if you wish to implement verification capabilities. If you are only implementing holding capabilities, you can skip to step 3.

The MATTR VII tenant is used to interact with the digital wallet as per OID4VP and ISO/IEC 18013-7 to request and verify mDocs. To enable this, you must first create a Verifier configuration on this tenant.

Create Verifier configuration

The verifier configuration is used to define the following:

  • What wallet applications the verifier can interact with.
  • How to invoke these wallet applications.
  • How to establish trust with this verifier tenant.
  • Workflow specific settings (e.g. cross-device/same-device).
  • How to handle the verification results.

Request

Make a request of the following structure to your tenant to create a Verifier configuration:

HTTP
PUT /v2/presentations/configuration

Request body

JSON
{
    "walletProviders": [
        {
            "id": "my-wallet-id",
            "authorizationEndpoint": "mdoc-openid4vp://"
        }
    ],
    "domains": ["example-verifier-web-application.com"],
    "supportedMode": "all",
    "redirectUris": ["https://example-verifier-web-application.com/presentation/callback"],
    "certificateCommonName": "{tenantDomain} Verifier",
    "certificateCountry": "NZ",
    "display": {
        "logoImage": {
            "url": "https://example-logo-image-url.com",
            "altText": "logo image"
        },
        "headerText": "Share your information.",
        "bodyText": "Please scan the QR code to the right to provide information required for this interaction.",
        "privacyPolicyUrl": "https://example-privacy-policy.com",
        "primaryColorHex": "#FFFFFF"
    },
    "resultAvailableInFrontChannel": true
}
  • walletProviders : This optional array can be used to define the digital wallets the tenant can create online presentation workflows with, and what URL schemes should be used to invoke these wallets.

    Incoming presentation verification requests can include a unique identifier of the wallet they want to invoke as part of the verification workflow:

    • If an identifier is provided and matches the id of one of the objects in the walletProviders array, the verifier tenant will invoke that specific wallet using its configured authorizationEndpoint.
    • If an identifier is provided and does not match the id of any of the objects in the walletProviders array, the request will fail.
    • If an identifier is not provided, the verifier tenant will use mdoc-openid4vp:// (default OID4VP scheme) to invoke any wallet.
  • domains : List of fully qualified domain names of verifier web applications who can request to create an online presentation session. This ensures the verifier tenant only accepts requests from known and trusted web applications. Note that localhost is not supported. You can use local tunneling services for testing.

  • supportedMode : Indicates whether a verifier supports only a same device flow, a cross device flow, or both.

  • redirectUris : Only required for same-device flows, and used to redirect the user back to the web application after completing interactions with the digital wallet. This can be any URI, including custom URI schemes.

  • certificateCommonName : Used to define the Common name of the verifier root certificate that will be created as part of this request. Wallets that are implementing certificate-based trust should be paying extra attention to this value as it would be used by the user to establish trust with the verifier.

  • certificateCountry : Used to define the ISO 31661 alpha-2 country code of the verifier root certificate that will be created as part of this request.

  • display : Only required for cross-device flows, and used to adjust the iframe modal appearance.

    • logoImage : Logo to be displayed on the top left corner of the iframe modal.
    • headerText : Header text displayed in the iframe modal.
    • bodyText : Optional body text displayed in the iframe modal, explaining the context in which the credentials will be shared.
    • privacyPolicyUrl : Optional privacy policy url to be displayed in the iframe modal.
    • primaryColorHex : Optional hex rgb triplet to indicate the primary color of the iframe modal.
  • resultAvailableInFrontChannel : Indicating whether or not the verification result should be returned directly to the web application (true) or only via a configured back-end (false).

Response

A successful 200 response indicates that Verifier configuration has been created/updated.

The response will include a certificatePem property, which is a PEM representation of the verifier root certificate created to represent this tenant. We will use it to establish trust between your wallet application and this verifier.

Configure trusted issuers

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. This certificate can be retrieved in one of two ways:

  • The Issuer can provide it directly to the Verifier out of band.
  • The Verifier can retrieve it from the Issuer’s metadata:
    1. Make a GET request to the Issuer’s /.well-known/openid-credential-issuer endpoint.
    2. Retrieve the mdoc_iacas_uri element from the response.
    3. Make a GET request to that URI to retrieve the IACAs list (for example for a MATTR VII Issuer tenant this URI would be {tenant_url}/v1/openid/iacas).

Request

Make a request of the following structure to your tenant to create a Truster Issuer:

HTTP
POST /v2/credentials/mobile/trusted-issuers

Request body

JSON
{
    "certificatePem": "-----BEGIN CERTIFICATE-----\r\nMIICUDCCAfWgAwIBAgIKVVqBlVonWFs3lTAKBggqhkjOPQQDAjAkMQswCQYDVQQG\r\nEwJOWjEVMBMGA1UEAwwMRXhhbXBsZSBJQUNBMB4XDTI0MDExMTAzMjYwMFoXDTM0\r\nMDEwODAzMjYwMFowJDELMAkGA1UEBhMCTloxFTATBgNVBAMMDEV4YW1wbGUgSUFD\r\nQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOHxm9MYkCvIvZc/MyoWGul8+tla\r\nFSSRVkDllFERbO/Tg7DOj4CJfYrhDJEuV04eRgcowBDhr9W/bvnTMZMa/RijggEN\r\nMIIBCTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E\r\nFgQUpS3hOCbmCUwu8n91X9CLS682cOkwOwYDVR0SBDQwMoYwaHR0cHM6Ly9odWRz\r\nb24tdGVuYW50LTAwMS52aWkuYXUzMDEubWF0dHJsYWJzLmlvMIGGBgNVHR8EfzB9\r\nMHugeaB3hnVodHRwczovL2h1ZHNvbi10ZW5hbnQtMDAxLnZpaS5hdTMwMS5tYXR0\r\ncmxhYnMuaW8vdjIvY3JlZGVudGlhbHMvbW9iaWxlL2lhY2FzL2VkNzQzMTllLTcy\r\nYTYtNDQwMS1iM2E1LTk0ZTk4MGZiZWJlYS9jcmwwCgYIKoZIzj0EAwIDSQAwRgIh\r\nAJxWGZvntq+hymL7zWwrlZo1Jz1+lWglu/MESdmUhTNFAiEAg+x5e3TzBxgHneIM\r\nVpTmZNOyZI3Hn17WRKkyKSg+5/8=\r\n-----END CERTIFICATE-----\r\n"
}
  • certificatePem: Use the PEM certificate of the IACA that is being used by the issuer to sign mDocs.

Add online verification capabilities into a web application

This step is only required if you wish to implement verification capabilities. If you are only implementing holding capabilities, you can skip to step 3.

Add online verification capabilities into your web application by using the following Verifier Web SDK functions:

1. Initialize the SDK

Before using any SDK functions you must initialize the SDK by calling the initialise function:

JavaScript
MATTRVerifierSDK.initialise({ apiBaseUrl })

apiBaseUrl should be replaced with the tenant_url of your MATTR VII verifier tenant, provided with your access credentials.

2. Create a new credential query
JavaScript
const credentialQuery = [
    {
        profile: 'mobile',
        docType: 'org.iso.18013.5.1.mDL',
        nameSpaces: {
            'org.iso.18013.5.1': {
                birthdate: {
                    intentToRetain: false
                },
                portrait: {
                    intentToRetain: false
                },
                resident_postal_code: {
                    intentToRetain: true
                }
            }
        }
    }
]
  • profile: Credential format of the credential that will be verified. Currently only mobile (mDocs) is supported.

  • docType: the mDL’s type. Confirm with the certificate issuer for what docType they are issuing. Some common examples include:

    • Mobile Driver License (org.iso.18013.5.1.mDL).
    • PhotoID (org.iso.23220.photoid.1).
    • Mobile Vehicle Registration Card (org.iso.7367.1.mVRC).
    • Health certificate (org.micov.vtr.1).
  • nameSpaces: Each namespace corresponds to a group of claims included in the credential. These can be claims that are part of a specific standard, jurisdiction or any other reference. The namespace would usually correspond to the requested docType.

    • intentToRetain (Optional): When set to true, the holder will be indicated that the verifier intends to retain this claim beyond the verification workflow. Defaults to false when not specified.

In this example the credentialQuery query will request for the birthdate, portrait and resident_postal_code claims from any credentials whose profile is mobile and docType is org.iso.18013.5.1.mDL.

It also sets intentToRetain as true for the resident postal code, indicating to the holder that the verifier will retain this claim beyond the verification workflow. The other two claims have intentToRetain as false indicating that the verifier will not retain any of these claims.

While intentToRetain defaults to false, it is explicitly set to false for birthdate and portrait in the example above for clarity purposes. If there is no intention to retain a claim, it is sufficient to simply exclude intentToRetain from the query.

3. Trigger a presentation request and share it with the wallet

As part of a digital interaction with the user, call the requestCredentials function with the created credential query. This will trigger the configured MATTR VII verifier tenant to create a presentation request and share it with the wallet:

JavaScript
const result = await MATTRVerifierSDK.requestCredentials({
    credentialQuery: [credentialQuery],
    challenge: MATTRVerifierSDK.utils.generateChallenge(), // replace with a challenge generated by the backend when applicable
    walletProviderId,
    mode: undefined, // auto detection base on browser user agent
    redirectUri, // required fields for save device mode
    crossDeviceCallback: {
        // required fields for cross device mode
        onComplete: (result) => {
            console.info(
                '<<< MATTRVerifierSDK.requestCredentials crossDeviceCallback.onComplete',
                result
            )
        },
        onFailure: (error) => {
            console.info(
                '<<< MATTRVerifierSDK.requestCredentials crossDeviceCallback.onFailure',
                error
            )
        }
    }
})
  • credentialQuery: Use the query created above.
  • challenge: Create a random and unique challenge to ensure the security of the verification process by preventing replay attacks. You can use this challenge to verify the verification response from the MATTR VII tenant.
  • walletProviderId: This value must match one of the values configured on your MATTR VII verifier tenant in Step 1 above.
  • mode: When set to undefined, the SDK will automatically choose the presentation flow based on the user agent’s browser (mobile agents will use same-device workflows while desktop agents will use cross-device workflows). You can set to either crossDevice or sameDevice to explicitly choose a presentation flow.
  • redirectUri: Only required for cross-device flows. Use the same value you configured on your MATTR VII verifier tenant in step 1 above.
  • crossDeviceCallback: Define how to handle success/failure cross device callbacks.

Integrate a backend into the verification workflow

This step is only required if you wish to adjust the workflow so that verification results are shared with a configured backend rather than directly with the frontend.

  1. Set resultAvailableInFrontChannel to false when you create the verifier configuration.
  2. Pass a random challenge to the web application and use it when calling the requestCredentials function.
  3. Retrieve the sessionId returned by the MATTR VII verifier tenant to your web application when verification is completed.
  4. Make a request of the following structure to your MATTR VII verifier tenant to retrieve the complete verification results:
HTTP
GET /v2/presentations/sessions/{sessionId}/result
  1. Validate the challenge included in the response to ensure it matches the challenge passed when creating the presentation session.
  2. Process the verification results and pass the required information back to the web application to continue the interaction based on your business logic.

Add online presentation capabilities into a wallet application

This step is only required if you wish to implement holding capabilities. If you are only implementing verification capabilities, you can skip this step.

Add online presentation capabilities into your digital wallet application by using the following React Native Holder SDK components:

JavaScript
// start a new presentation session
const createPresentationSessionResult =
    await wallet.credential.mobile.createOnlinePresentationSession({
        authorisationRequestUri: '...'
    })
 
if (createPresentationSessionResult.isErr()) {
    // Define how to handle any errors creating a new presentation session
}
 
const session = createPresentationSessionResult.value
// Render the verifier information stored in `session.verifiedBy`.
// Render the list of matched mDocs for each received request stored in `session.matchedCredentials` for user to select.
 
// Construct and send a presentation response with the selected credentials
const sendResponseResult = await session.sendResponse({ credentialIds })
 
// In case of an error, you could either terminate the session or try and create a new createOnlinePresentationSession again
if (sendResponseResult.isErr()) {
    await session.terminateSession()
}
  • authorisationRequestUri: This should match the authorizationEndpoint defined in your MATTR VII verifier tenant configured in Step 1 above.