Remote mobile verification quickstart guide
This quickstart is for evaluating the MATTR Pi mDocs Mobile Verifier SDKs. In about 15-20 minutes you will configure a MATTR VII verifier tenant, run a sample verifier mobile app (iOS, Android, or React Native) on a physical device, and use it to verify an mDoc presented from a wallet application on the same device using the remote presentation workflow defined by OID4VP and ISO/IEC 18013-7:2025 Annex B.
This is an app-to-app flow. The verifier app invokes a separate wallet app installed on the same device to request the credential, and the wallet returns the presentation to the verifier. It is not the browser-based Digital Credentials API flow: both apps run on the same physical device and exchange the OID4VP request and response directly between each other.
Estimated time: 15-20 minutes. This covers the verifier setup and verification flow. Allow additional time to build and run the sample holder app from the Holder SDK quickstart guide, which you need before Part 3.
Use this guide as a fast evaluation path to see the Mobile Verifier SDK working end-to-end on a real device. For detailed information and API examples, explore the tutorial and reference documentation tailored for each platform.
User experience
In this quickstart you will perform this exact flow yourself using a MATTR VII verifier tenant, the sample verifier app, and a wallet that supports remote presentation acting as the holder. MATTR GO Hold does not support remote presentation, so this guide uses the sample holder app you can build with the Holder SDK quickstart guide:
- A relying party uses the Mobile Verifier SDK to embed a remote verification workflow into a mobile application.
- When a user interacts with the mobile application, a matching wallet application installed on their mobile device is invoked to request an mDoc for verification.
- The user consents to sharing the requested information.
- The user's wallet application shares the matching mDoc with the MATTR VII tenant configured by the Mobile Verifier SDK to perform the verification workflow.
- The MATTR VII tenant performs the required checks and returns the verification results via the Mobile Verifier SDK to the verifier application.
- The user journey continues based on the verification results.
Prerequisites
- Access to the MATTR Pi mDocs Mobile Verifier SDK for your chosen platform (iOS, Android, or React Native). Apply for access here.
- MATTR VII tenant access via the MATTR Portal. Apply for access here.
- A physical mobile device to run the verifier app, with a wallet that supports remote presentation as per ISO/IEC 18013-7 and OID4VP installed on the same device. MATTR GO Hold does not support remote presentation, so before you reach Part 3 you will need to build and run the sample holder app from the Holder SDK quickstart guide on that same device. You use it in Part 3 to claim and present a credential, so allow time to complete that quickstart as well.
- Development environment set up for your chosen platform (Xcode for iOS, Android Studio for Android, or a React Native / Expo development environment with Node.js 18+).
Steps
In this quickstart you will:
- Configure a MATTR VII verifier tenant to handle verification requests.
- Download, configure, and run a local sample verifier project for your platform.
- Claim a test credential into a wallet on the same device and verify it remotely.
- Review the structure of the sample project so you can see how to integrate the SDK into your own app.
Use the tabs below to follow platform-specific setup steps.
Part 1: Configure the MATTR VII verifier tenant (5 minutes)
These steps configure your verifier tenant so the sample verifier app can request and verify mDocs issued by a trusted issuer.
Create a verifier application configuration
This creates the verifier application that the Mobile Verifier SDK uses when interacting with the MATTR VII tenant to request and receive credential presentations.
- Log into the MATTR Portal.
- Expand the Credential Verification menu in the left-hand navigation panel.
- Select Applications.
- Select Create new.
- Enter a meaningful Name for your application (e.g. "My iOS Mobile Verifier Application").
- Use the Type dropdown to select
iOS. - 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. For this evaluation the value is
not validated, so if you don't have it to hand you can enter any suitably formatted placeholder
string (e.g.
ABCDE12345) to continue. - Enter the bundle identifier you will use for the sample app in the Bundle ID field (e.g.
com.yourname.mobileverifier). You will set this same value on the sample app in Part 2. - In the OID4VP configuration section, enter a redirect URI structured as
{your_app_bundleId}://my/path(e.g.com.yourname.mobileverifier://my/path). This is the URI the user is redirected to after presenting the credential from their wallet. - Select Create.
- Make note of the generated application
ID. You will use this value to configure the sample app later.
- Log into the MATTR Portal.
- Expand the Credential Verification menu in the left-hand navigation panel.
- Select Applications.
- Select Create new.
- Enter a meaningful Name for your application (e.g. "My Android Mobile Verifier Application").
- Use the Type dropdown to select
Android. - Enter the package name you will use for the sample app in the Package Name field (e.g.
com.yourname.mobileverifier). You will set this same value on the sample app in Part 2. - In the Signing certificate thumbprints field, enter a temporary placeholder value (e.g.
3A9F6C1D4E8B72F0A5C3D6E19B4F8A2C7D1E0B9F3A6C5D4E7B8F2A1C9D0E3F5B). You will update this with your app's real signing certificate thumbprint in Part 2. - In the OID4VP configuration section, enter a redirect URI structured as
{your_app_packageName}://oid4vp-callback(e.g.com.yourname.mobileverifier://oid4vp-callback). This is the URI the user is redirected to after presenting the credential from their wallet. - Select Create.
- Make note of the generated application
ID. You will use this value to configure the sample app later.
A React Native app runs on both iOS and Android, and the MATTR VII tenant validates requests differently for each platform. Create a verifier application for the platform you intend to run the sample app on, following the steps in the iOS or Android tab.
Create a supported wallet configuration
This defines the URI scheme the MATTR VII tenant uses to invoke the wallet application as part of the remote verification workflow.
- Expand the Credential Verification menu in the left-hand navigation panel.
- Select Supported wallets.
- Select Create new.
- Enter a meaningful Name for the supported wallet (e.g. "My Supported Wallet").
- Enter
mdoc-openid4vp://in the Authorization Endpoint field. This is the default OID4VP scheme used to invoke the wallet application. - Select Create.
More information on applying different URI schemes and the resulting user experience can be found on the workflow page.
Configure a trusted issuer
In this quickstart you will add a MATTR-provided demo issuer certificate so your verifier accepts mDocs issued by this issuer.
- Select Trusted issuers under the Credential Verification menu.
- Select Create new.
- Copy and paste the following certificate into the Certificate PEM file field:
-----BEGIN CERTIFICATE-----
MIICYzCCAgmgAwIBAgIKXhjLoCkLWBxREDAKBggqhkjOPQQDAjA4MQswCQYDVQQG
EwJBVTEpMCcGA1UEAwwgbW9udGNsaWZmLWRtdi5tYXR0cmxhYnMuY29tIElBQ0Ew
HhcNMjQwMTE4MjMxNDE4WhcNMzQwMTE1MjMxNDE4WjA4MQswCQYDVQQGEwJBVTEp
MCcGA1UEAwwgbW9udGNsaWZmLWRtdi5tYXR0cmxhYnMuY29tIElBQ0EwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAASBnqobOh8baMW7mpSZaQMawj6wgM5e5nPd6HXp
dB8eUVPlCMKribQ7XiiLU96rib/yQLH2k1CUeZmEjxoEi42xo4H6MIH3MBIGA1Ud
EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRFZwEOI9yq
232NG+OzNQzFKa/LxDAuBgNVHRIEJzAlhiNodHRwczovL21vbnRjbGlmZi1kbXYu
bWF0dHJsYWJzLmNvbTCBgQYDVR0fBHoweDB2oHSgcoZwaHR0cHM6Ly9tb250Y2xp
ZmYtZG12LnZpaS5hdTAxLm1hdHRyLmdsb2JhbC92Mi9jcmVkZW50aWFscy9tb2Jp
bGUvaWFjYXMvMjk0YmExYmMtOTFhMS00MjJmLThhMTctY2IwODU0NWY0ODYwL2Ny
bDAKBggqhkjOPQQDAgNIADBFAiAlZYQP95lGzVJfCykhcpCzpQ2LWE/AbjTGkcGI
SNsu7gIhAJfP54a2hXz4YiQN4qJERlORjyL1Ru9M0/dtQppohFm6
-----END CERTIFICATE------ Select Add.
Part 2: Configure and run the sample verifier app (5-10 minutes)
In this section you will download, configure, and run a sample verifier app that uses the Mobile Verifier SDK. This sample app is the completed result of the mobile verification tutorial.
-
Access the sample verifier codebase by either:
-
Cloning the MATTR Sample Apps repository:
Clone sample apps git clone https://github.com/mattrglobal/sample-apps.git -
Or downloading just the iOS sample verifier project using download-directory.github.io.
-
-
Use Xcode to open the
.xcodeprojfile in the project's folder. You can find it in thesample-apps/ios-remote-verification-tutorial-sample-appdirectory. -
Drag the
MobileCredentialVerifierSDK-*version*.xcframeworkfolder (obtained from MATTR as part of the SDK package) into your project. -
Configure
MobileCredentialVerifierSDK-*version*.xcframeworkto Embed & sign. -
Set the bundle identifier you entered in Part 1 for the project in the Xcode project settings (e.g.
com.yourname.mobileverifier). -
Open the
Constantsfile and update it with your tenant and application details:Constants enum Constants { static let tenantHost = URL(string: "https://your-tenant.vii.mattr.global")! static let applicationID = "your-application-id" }tenantHost: Replace with the URL of your MATTR VII tenant, available in the MATTR Portal under Platform Management > Tenant.applicationID: Replace with theidreturned when you created the verifier application in Part 1.
-
Run the project on a physical iOS device.
-
Access the sample verifier codebase by either:
-
Cloning the MATTR Sample Apps repository:
Clone sample apps git clone https://github.com/mattrglobal/sample-apps.git -
Or downloading just the Android sample verifier project using download-directory.github.io.
-
-
Open the project in Android Studio. You can find it in the
sample-apps/android-remote-verification-tutorial-sample-appdirectory. -
Unzip the
mobile-credential-verifier-*version*.zipfile (obtained from MATTR as part of the SDK package) and copy the unzippedglobalfolder into the project'srepofolder. -
Sync the project with Gradle files to recognize the new module.
-
Open
app/build.gradle.ktsand replace the placeholderapplicationIdwith the package name you entered in Part 1 (e.g.com.yourname.mobileverifier).The deep link scheme in
AndroidManifest.xmlis bound to${applicationId}, so changing this value automatically updates the scheme that the wallet will redirect to. -
Open the
Constantsfile and update it with your tenant and application details:Constants object Constants { const val TENANT_HOST = "https://your-tenant.vii.mattr.global" const val APPLICATION_ID = "your-application-id" }TENANT_HOST: Replace with the URL of your MATTR VII tenant, available in the MATTR Portal under Platform Management > Tenant.APPLICATION_ID: Replace with theidreturned when you created the verifier application in Part 1.
-
Run the project on a physical Android device.
-
Retrieve your app's signing certificate thumbprint and update the verifier application configuration:
-
Open a terminal inside your project's root folder and run:
Retrieve signing certificate ./gradlew signingReport -
Locate the
SHA-256value in theVariant: debugsection, remove all colons (:), and convert all letters to lowercase:Example conversion echo '91:F7:CB:F9:D6:81:53:1B:C7:A5:8F:B8:33:CC:A1:4D:AB:ED:E5:09:C5' | tr -d ':' | tr 'A-F' 'a-f' -
In the MATTR Portal, edit your verifier application and replace the placeholder Signing certificate thumbprints value with this thumbprint.
This thumbprint is only valid for your debug builds. If you intend to publish your app, repeat this process with the release signing certificate. Refer to Android App Signing for more information.
-
-
Access the sample verifier codebase by either:
-
Cloning the MATTR Sample Apps repository:
Clone sample apps git clone https://github.com/mattrglobal/sample-apps.git -
Or downloading just the React Native sample verifier project using download-directory.github.io.
-
-
Open the project in your code editor. You can find it in the
sample-apps/react-native-remote-verification-tutorial/react-native-remote-verification-tutorial-completedirectory. -
Open
app.config.tsand set the app identifiers, each under its marker comment, to the bundle ID / package name you entered in Part 1 (e.g.com.yourname.mobileverifier):-
Update the
bundleIdentifier(iOS) value under the// Update the bundle identifiercomment:app.config.ts bundleIdentifier: "com.yourname.mobileverifier", -
Update the
package(Android) value under the// Update the package namecomment:app.config.ts package: "com.yourname.mobileverifier", -
Add the iOS custom URL scheme under the
// Update the scheme propertycomment. This registers the scheme the wallet uses to redirect back to your app on iOS devices. Set it to your iOS bundle identifier:app.config.ts scheme: "com.yourname.mobileverifier",
-
-
Open the
Constants.tsfile and update it with your tenant and application details:Constants.ts import { Platform } from "react-native"; /** * Configuration values used to initialize the SDK and request credentials. * * Replace these placeholders with your own values before running the app: * - `TENANT_HOST`: the URL of your MATTR VII tenant, available in the MATTR Portal under * Platform Management > Tenant. * - `IOS_APPLICATION_ID` / `ANDROID_APPLICATION_ID`: the `id` returned when you created the verifier * application configuration in the MATTR Portal under Credential Verification > Applications. * iOS and Android each use their own verifier application, because the redirect URI registered on * the application must match that platform's URL scheme (see `app.config.ts`). Configure one * application ID per platform. */ const IOS_APPLICATION_ID = "your-ios-application-id"; const ANDROID_APPLICATION_ID = "your-android-application-id"; export const Constants = { TENANT_HOST: "https://your-tenant.vii.mattr.global", // Resolves to the verifier application ID for the current platform. APPLICATION_ID: Platform.OS === "ios" ? IOS_APPLICATION_ID : ANDROID_APPLICATION_ID, };TENANT_HOST: Replace with the URL of your MATTR VII tenant, available in the MATTR Portal under Platform Management > Tenant.IOS_APPLICATION_IDandANDROID_APPLICATION_ID: Replace the constant for the platform you are running with theidreturned when you created the verifier application in Part 1. To run on both platforms, create a verifier application for each (see the callout in Part 1) and set both constants.APPLICATION_ID: Resolves to the verifier applicationidfor the current platform at runtime. The SDK reads this value when requesting credentials.
-
With the app files configured, install the dependencies:
Install dependencies yarn installGenerate the native project files:
Generate project files yarn expo prebuildThen run the app on a physical device for your target platform:
Run iOS application yarn ios --deviceRun Android application yarn android --device -
Android only: Retrieve your app's signing certificate thumbprint and update the verifier application configuration:
Retrieve signing certificate cd android && ./gradlew signingReportLocate the
SHA-256value in theVariant: debugsection, remove all colons (:), and convert all letters to lowercase:Example conversion echo '91:F7:CB:F9:D6:81:53:1B:C7:A5:8F:B8:33:CC:A1:4D:AB:ED:E5:09:C5' | tr -d ':' | tr 'A-F' 'a-f'In the MATTR Portal, edit your verifier application and replace the placeholder Signing certificate thumbprints value with this thumbprint.
This thumbprint is only valid for your debug builds. If you intend to publish your app, repeat this process with the release signing certificate. Refer to Android App Signing for more information.
Part 3: Claim and verify a credential (5 minutes)
Claim a credential to present
To test the verification flow, you need a compatible mDoc in a wallet that supports remote presentation on the same device as the verifier app. Use the sample holder app you build with the Holder SDK quickstart guide to claim a demo mDL credential issued by the MATTR demo issuer you added as a trusted issuer in Part 1.
- Build and run the sample holder app on the device running the sample verifier app, following Part 1 of the Holder SDK quickstart guide.
- In the sample holder app, select Claim Credential (you may need to allow the app to access your camera).
- Scan the following QR code:

- Follow the on-screen instructions to claim the credential into the sample holder app.
This credential will be used in the next step when you test the remote verification flow.
Verify the credential
- Launch the sample verifier app and select Request credentials.
- You will be redirected to the sample holder app, which displays what information is requested for verification.
- Select the credential you claimed in the previous step and consent to sharing the requested information.
- You will be redirected back to the sample verifier app, which displays the verification results.
Behind the scenes, the Mobile Verifier SDK started a presentation session with your MATTR VII tenant, invoked the wallet, and surfaced the verification results returned by the tenant according to OID4VP and ISO/IEC 18013-7:2025 Annex B.
Review the codebase
The sample verifier application uses the Mobile Verifier SDK to verify mDocs presented remotely from a wallet on the same device. Once you have the sample application running, use this section to inspect the key SDK calls you will reuse in your own application.
Initialize the SDK
The SDK is initialized with your tenant host configuration so it knows which MATTR VII tenant to interact with.
let platformConfiguration = PlatformConfiguration(
tenantHost: Constants.tenantHost
)
do {
mobileCredentialVerifier = MobileCredentialVerifier.shared
try mobileCredentialVerifier.initialize(platformConfiguration: platformConfiguration)
} catch {
print(error.localizedDescription)
}tenantHost: URL of your MATTR VII tenant, defined in theConstantsfile.
val platformConfiguration = PlatformConfiguration(
tenantHost = URL(Constants.TENANT_HOST)
)
lifecycleScope.launch {
MobileCredentialVerifier.initialize(
context = this@MainActivity, platformConfiguration = platformConfiguration
)
}tenantHost: URL of your MATTR VII tenant, defined in theConstantsfile.
const result = await initialize({
platformConfiguration: { tenantHost: Constants.TENANT_HOST },
});
if (result.isErr()) {
console.error("Failed to initialize SDK:", result.error);
}tenantHost: URL of your MATTR VII tenant, defined in theConstantsfile. The SDK returns aResult, so checkresult.isErr()rather than relying on a thrown exception.
Create a presentation request
A presentation request defines the type of credential and the specific data elements being requested for verification.
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
]
]
)docType: The type of credential being requested (e.g.org.iso.18013.5.1.mDL).namespaces: A dictionary mapping each namespace to its requested attributes. Each attribute is a key with a Boolean indicating whether the verifier intends to retain this attribute (true) or not (false).
val mobileCredentialRequest = MobileCredentialRequest(
docType = "org.iso.18013.5.1.mDL", namespaces = NameSpaces(
mapOf(
"org.iso.18013.5.1" to DataElements(
mapOf(
"family_name" to false, "given_name" to false, "birth_date" to false
)
)
)
)
)docType: The type of credential being requested (e.g.org.iso.18013.5.1.mDL).namespaces: A map of each namespace to its requested attributes. Each attribute is a key with a Boolean indicating whether the verifier intends to retain this attribute (true) or not (false).
const mobileCredentialRequest = {
docType: "org.iso.18013.5.1.mDL",
namespaces: {
"org.iso.18013.5.1": {
family_name: false,
given_name: false,
birth_date: false,
},
},
};docType: The type of credential being requested (e.g.org.iso.18013.5.1.mDL).namespaces: An object mapping each namespace to its requested attributes. Each attribute is a key with a Boolean indicating whether the verifier intends to retain this attribute (true) or not (false).
Request credentials from the wallet application
This starts a presentation session with the MATTR VII tenant and redirects the user to a matching wallet application.
let onlinePresentationResult = try await mobileCredentialVerifier.requestMobileCredentials(
request: [mobileCredentialRequest],
challenge: UUID().uuidString,
applicationId: Constants.applicationID
)request: Array ofMobileCredentialRequestobjects defining what information to request.challenge: Unique challenge to identify this presentation session and prevent replay attacks. Generate a new challenge for every request.applicationId: Theidreturned when you created the verifier application configuration.
val onlinePresentationResult = MobileCredentialVerifier.requestMobileCredentials(
activity = activity,
request = listOf(mobileCredentialRequest),
applicationId = Constants.APPLICATION_ID
)activity: Defines the current activity context.request: List ofMobileCredentialRequestobjects defining what information to request.applicationId: Theidreturned when you created the verifier application configuration.
const result = await requestMobileCredentials({
request: [mobileCredentialRequest],
applicationId: Constants.APPLICATION_ID,
challenge: Crypto.randomUUID(),
});request: Array ofMobileCredentialRequestobjects defining what information to request.applicationId: Theidreturned when you created the verifier application configuration.challenge: A unique, unpredictable value to identify this presentation session and prevent replay attacks. Generate a new challenge for every request.
Handle the redirect from the wallet
After the wallet presents the credential, the user is redirected back to the verifier app via the custom URL scheme configured for the sample app in Part 2.
.onOpenURL { url in
// Navigate to response screen
viewModel.navigationPath.append(NavigationState.viewResponse)
viewModel.mobileCredentialVerifier.handleDeepLink(url)
}Add this modifier to your SwiftUI view to navigate to the response screen and pass the redirect URL
to the SDK's handleDeepLink method. The SDK processes the response and updates the
receivedDocuments variable with the verification results.
The SDK handles the redirect via the Openid4VpCallbackActivity declared in your
AndroidManifest.xml. Register the callback activity with an intent filter that matches the redirect
URI of your verifier application:
<activity
android:name="global.mattr.mobilecredential.verifier.a2apresentation.callback.Openid4VpCallbackActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="com.yourname.mobileverifier"
android:host="oid4vp-callback" />
</intent-filter>
</activity>android:scheme: Must match the redirect custom scheme you defined when you created the verifier application.android:host: Must match the redirect host you defined when you created the verifier application.
Handling the redirect differs by platform:
-
iOS: Forward the wallet's redirect URL to the SDK with
handleDeepLinkso it can complete the pendingrequestMobileCredentialscall:Handle redirect URL (iOS) useEffect(() => { if (Platform.OS !== "ios") { return; } const subscription = Linking.addEventListener("url", ({ url }) => { handleDeepLink({ url }); }); return () => subscription.remove(); }, []); -
Android: The
withOpenid4VpCallbackActivityconfig plugin declares the SDK'sOpenid4VpCallbackActivityinAndroidManifest.xml, bound to{your_packageName}://oid4vp-callback. The SDK handles the redirect automatically, sorequestMobileCredentialsresolves directly and no additional code is required.
Handle the presentation response
The
requestMobileCredentials
method returns an OnlinePresentationSessionResult object containing the presentation details, any
errors encountered, and the verification status of the credentials. The sample app reads the
credentials from this result, stores them, and renders them in a dedicated view.
guard let receivedCredentials = onlinePresentationResult.mobileCredentialResponse?.credentials else {
let errorMessage = onlinePresentationResult.error?.message ?? "No error message"
print("No response received: \(errorMessage)")
return
}
receivedDocuments = receivedCredentialsmobileCredentialResponse: Contains the verified credentials and their claims.error: Any error that occurred during the verification process.credentials: A list of presented credentials with their data, status, and verification results.
The sample app assigns the result to the receivedDocuments variable, which a DocumentView then
renders. A DocumentViewModel converts each MobileCredentialPresentation (docType, verification
result, claims, and claim errors) into a human-readable format for display.
_receivedDocuments.value =
onlinePresentationResult.mobileCredentialResponse?.credentials ?: emptyList()mobileCredentialResponse: Contains the verified credentials and their claims.error: Any error that occurred during the verification process.credentials: A list of presented credentials with their data, status, and verification results.
The sample app assigns the result to the _receivedDocuments state flow, which a DocumentView
composable then renders. The composable reads the docType and verification result and flattens
document.claims into a list of label and value pairs for display.
const session = result.value;
if (!session.isSuccess) {
console.error(`Verification session failed: ${session.error.message}`);
return;
}
const response = session.mobileCredentialResponse;
setVerificationResults(response ?? null);result.value: TheOnlinePresentationSessionResult. Checksession.isSuccessto distinguish a successful session from a failed one (session.error).mobileCredentialResponse: Contains the verified credentials and their claims.credentials: A list of presented credentials with their data, status, and verification results.
The sample app stores the response and renders it in a VerificationResultsModal, which reads each
MobileCredentialPresentation (docType, verification result, claims, and claim errors) and displays
it in a human-readable format.
Next steps
- For your evaluation:
- Note how long it took to configure the tenant, run the sample app, and complete a remote verification.
- Consider how the sample's presentation request and result handling map to your real verification use cases (for example, which attributes you would request and how you would display them).
- Explore the detailed tutorial for step-by-step implementation guidance.
- Review the SDK reference documentation for your platform:
- Learn more about the remote verification workflow.
How would you rate this page?
Last updated on