React Native Verifier SDK v10.0.0 Migration Guide
A comprehensive guide to migrating to React Native Verifier SDK v10.0.0, covering breaking changes, new features, and step-by-step migration instructions.
Overview
This guide provides a comprehensive overview of the changes introduced in the React Native Verifier SDK v10.0.0, including breaking changes, new features, and migration steps.
This release:
- Adds the SDK Backend, which is required in this release. Every SDK and app instance is
registered with, and licensed by, your MATTR VII tenant at initialization. This affects in-person
(proximity) verification most, because it previously needed no MATTR VII tenant at all. Remote
mobile (app-to-app) verification already required a
platformConfiguration, and thatplatformConfigurationis now mandatory for every initialization. - Reshapes verification and presentation results into discriminated unions, so TypeScript enforces which fields are available.
- Returns typed
Resultvalues from six more functions, so expected failures surface as values you can handle rather than as unrecognized thrown errors. - Renames and reorganizes the error enums and the revocation status list API.
Key Features
- SDK Backend (required): The React Native Verifier SDK now connects to a backend MATTR VII
tenant, tying each SDK and app instance to your tenant. On first initialization the SDK registers
the app instance with the tenant specified in
platformConfigurationand obtains a license, and on subsequent initializations the existing license is renewed automatically. This lets you view registered and active app instances directly from your tenant for operational insight, and establishes a remote management channel we expect to extend in future releases, for example remote syncing of trusted issuer lists and eventing. Network access is required when registration or renewal is performed. - Predictable result types: Online presentation results, revocation status list refresh results, and verification results are now discriminated unions. The fields that are guaranteed on each branch are no longer optional, so TypeScript enforces correct handling after narrowing.
- Typed, handleable errors: Six functions that previously resolved a plain value now return a
Result, invalid arguments raise a typedInvalidParamscode instead of a genericError, and a newMobileCredentialVerifierReactNativeErrorTypeenum separates bridge errors from native SDK errors. - Cross-platform alignment: Error codes, the revocation status list API, and result shapes now match the iOS and Android Verifier SDKs, minimizing divergence for teams maintaining cross-platform applications.
- Correlate app instances:
platformConfigurationaccepts an optionalexternalReferenceId, a developer-defined identifier you can use to correlate an app instance with a record in MATTR VII. - General stability and performance improvements: Multiple refinements reduce integration friction, increase consistency, and improve overall reliability.
Breaking Changes
This section outlines the breaking changes introduced in v10.0.0 that require updates to your existing implementation:
| # | Change | Impact |
|---|---|---|
| 1 | The SDK Backend is now required: platformConfiguration is mandatory on initialize, which now also registers the app instance and obtains a license | Always supply a platformConfiguration. Handle the new InvalidLicense and FailedToRegister errors. See Supply platformConfiguration at initialization. |
| 2 | The minimum supported React Native version is now 0.83 | Upgrade your application to React Native 0.83 or later before installing this version. |
| 3 | applicationId removed from requestMobileCredentials and fetchAppleWalletConfiguration | Remove the argument from both call sites and supply it via platformConfiguration instead. |
| 4 | Six functions now return a Result: getTrustedIssuerCertificates, deleteTrustedIssuerCertificate, registerForNfcDeviceEngagement, deregisterForNfcDeviceEngagement, refreshRevocationStatusLists, and getRevocationStatusListsCacheInfo | Handle the Result instead of using the resolved value directly. These functions can still throw, so keep a try/catch alongside the Result handling. See Handle the new Result returns. |
| 5 | Revocation status list methods and types renamed from TrustedIssuer terminology to Revocation terminology | Rename updateTrustedIssuerStatusLists to refreshRevocationStatusLists, getTrustedIssuerStatusListsCacheInfo to getRevocationStatusListsCacheInfo, and the corresponding types. See Update revocation status list method and type names. |
| 6 | OnlinePresentationSessionResult is now an isSuccess-discriminated union instead of a single object with optional fields | Narrow on isSuccess. error is guaranteed on failure and absent on success. See Narrow results on isSuccess. |
| 7 | RevocationStatusListsRefreshResult is now an isSuccess-discriminated union, and the success field has been replaced by isSuccess | Replace result.success with result.isSuccess and narrow before reading failedLists. See Narrow results on isSuccess. |
| 8 | MobileCredentialResponse.credentials and credentialErrors are now required arrays | Remove optional chaining and null checks. Both are always present, as empty arrays when there are no items. |
| 9 | VerificationResult is now discriminated on verified, and reason is required when verified is false | Remove optional chaining on reason and narrow on verified before reading it. |
| 10 | nextUpdate narrowed from Date | null | undefined to Date | undefined | Remove explicit null checks. Use undefined checks or optional chaining instead. |
| 11 | Invalid or malformed arguments now raise the InvalidParams error code instead of a synchronous Error | Update any code that matched on the previous Invalid arguments for '<function>' function: ... message. See Keep argument objects to documented fields. |
| 12 | Android now rejects unrecognized keys in argument objects with an InvalidParams error | Ensure argument objects contain only documented fields so behavior is consistent across platforms. iOS still ignores unknown keys. |
| 13 | Renamed and moved error enum members, including SessionStatus, UnknownError, Connectivity, SessionTimedOut, and PlatformNotSupported | Update imports, type references, and error handling. See Update renamed and removed exports. |
| 14 | All runtime validator exports removed | Remove imports of the *Validator exports and AppleWalletSchema. Use the exported TypeScript types instead. |
| 15 | New error codes added to MobileCredentialVerifierErrorType and ProximityPresentationSessionErrorType, plus a new MobileCredentialVerifierReactNativeErrorType enum | Update exhaustive switch statements over these error types. See Handle new error codes. |
Migration Steps
Create a verifier application on your MATTR VII tenant
The SDK Backend requires a verifier application configured on the MATTR VII tenant your SDK connects to. If you already use remote mobile (app-to-app) verification you will have created one, and the same application is reused for the SDK Backend. If you have not, create one now.
React Native bridges both iOS and Android, and each platform is identified differently, so create one verifier application per platform you ship.
Create the iOS verifier application
- Log in to the MATTR Portal and expand the Credential verification section in the left-hand navigation panel.
- Select Applications, then select the Create new button.
- Use the Name text box to insert a meaningful and friendly name for your application, for
example
My RN Verifier Application (iOS). - Use the Type radio button to select iOS.
- Use the Team ID text box to insert your Apple Developer Team ID.
- Use the Bundle ID text box to insert the Bundle ID of your iOS app.
- Select the Create button to create the application and display its detail screen.
- Copy and record the
IDvalue. You use it as theapplicationIdfor the iOS target when initializing the SDK.
Your tenant validates the Team ID and Bundle ID against the app build that registers with it, so either value not matching your Xcode project configuration fails registration and the SDK does not initialize.
Create the Android verifier application
- Return to Applications in the Credential verification section and select the Create new button again.
- Use the Name text box to insert a meaningful and friendly name for your application, for
example
My RN Verifier Application (Android). - Use the Type radio button to select Android.
- Use the Package name text box to insert the package name of your Android application.
- Use the Signing certificate thumbprints field to insert the SHA-256 hex-encoded fingerprints of the signing key certificates used to sign your APK or app bundle. Refer to Android app signing for more information.
- Select the Create button to create the application and display its detail screen.
- Copy and record the
IDvalue. You use it as theapplicationIdfor the Android target when initializing the SDK.
Your tenant validates the package name and signing certificate thumbprints against the app build that registers with it, so either value not matching your release configuration fails registration and the SDK does not initialize.
Refer to the SDK Backend guide for the remaining SDK Backend settings, including attestation and the maximum time an app instance can operate offline.
Supply platformConfiguration at initialization
platformConfiguration is now required on initialize. It registers the app instance with your
MATTR VII tenant and obtains a license on first initialization, and renews that license on subsequent
initializations.
Because each platform has its own verifier application, select the correct applicationId at
runtime with Platform.OS:
import { initialize } from "@mattrglobal/mobile-credential-verifier-react-native";
+ import { Platform } from "react-native";
- await initialize();
+ const applicationId =
+ Platform.OS === "android"
+ ? "your-android-verifier-application-id"
+ : "your-ios-verifier-application-id";
+
+ await initialize({
+ platformConfiguration: {
+ tenantHost: "https://your-tenant.vii.mattr.global",
+ applicationId,
+ },
+ });tenantHost: The URL of your MATTR VII tenant. This must be the tenant where your verifier applications are configured.applicationId: Theidof the verifier application that matches the current platform target.
If you already configured platformConfiguration for remote mobile verification, add the
applicationId you previously passed to requestMobileCredentials:
await initialize({
platformConfiguration: {
tenantHost: "https://your-tenant.vii.mattr.global",
+ applicationId,
},
});Network access is required the first time the SDK initializes, and when the license is renewed on subsequent initializations. Refer to token validity and offline use for how long an app instance can operate without connectivity.
Handle license and registration errors
Because the SDK Backend registers and licenses the SDK, initialize may now return two new errors:
InvalidLicense: the SDK license failed to validate or has expired.FailedToRegister: registering the app instance with MATTR VII failed.
const result = await initialize({ platformConfiguration });
if (result.isErr()) {
switch (result.error.type) {
+ case MobileCredentialVerifierErrorType.FailedToRegister:
+ // Registration with the MATTR VII tenant failed. Check connectivity and configuration.
+ break;
+ case MobileCredentialVerifierErrorType.InvalidLicense:
+ // The SDK license is missing, invalid, or expired.
+ break;
// ... other cases
}
}InvalidLicense may also be returned by the functions that require a valid license:
addTrustedIssuerCertificatesgetTrustedIssuerCertificatesdeleteTrustedIssuerCertificatedestroyfetchAppleWalletConfigurationrequestMobileCredentialsAppleWallet.requestMobileCredentialssendProximityPresentationRequestregisterForNfcDeviceEngagementderegisterForNfcDeviceEngagementrefreshRevocationStatusListsgetRevocationStatusListsCacheInfo
It is also reported through the onError callback of createProximityPresentationSession.
initialize may also now return StorageInitialization when SDK storage cannot be initialized.
Remove the applicationId argument from requestMobileCredentials and fetchAppleWalletConfiguration
The applicationId parameter has been removed from both functions. The SDK now uses the
applicationId supplied in platformConfiguration at initialization:
const result = await requestMobileCredentials({
request: [mobileCredentialRequest],
challenge,
- applicationId: "your-verifier-application-id",
}); const result = await fetchAppleWalletConfiguration({
request: mobileCredentialRequest,
merchantId,
- applicationId: "your-verifier-application-id",
});Handle the new Result returns
Six functions that previously resolved a plain value now return a neverthrow Result, so their
expected error cases surface as typed values you can handle. These functions can still throw, so a
try/catch is still required alongside handling the Result.
| Function | Previously | Now |
|---|---|---|
getTrustedIssuerCertificates | Promise<TrustedIssuerCertificate[]> | Promise<Result<TrustedIssuerCertificate[], GetTrustedIssuerCertificatesError>> |
deleteTrustedIssuerCertificate | Promise<void> | Promise<Result<void, DeleteTrustedIssuerCertificateError>> |
registerForNfcDeviceEngagement | Promise<void> | Promise<Result<void, RegisterForNfcDeviceEngagementError>> |
deregisterForNfcDeviceEngagement | Promise<void> | Promise<Result<void, DeregisterForNfcDeviceEngagementError>> |
refreshRevocationStatusLists | Promise<RevocationStatusListsRefreshResult> | Promise<Result<RevocationStatusListsRefreshResult, RefreshRevocationStatusListsError>> |
getRevocationStatusListsCacheInfo | Promise<GetRevocationStatusListsCacheInfo> | Promise<Result<GetRevocationStatusListsCacheInfo, GetRevocationStatusListsCacheInfoError>> |
The matching error types are now exported from the package: GetTrustedIssuerCertificatesError,
DeleteTrustedIssuerCertificateError, RegisterForNfcDeviceEngagementError,
DeregisterForNfcDeviceEngagementError, RefreshRevocationStatusListsError, and
GetRevocationStatusListsCacheInfoError.
Update each call site to handle the Result:
- const certificates = await getTrustedIssuerCertificates();
+ try {
+ const certificatesResult = await getTrustedIssuerCertificates();
+
+ if (certificatesResult.isErr()) {
+ // Handle the error from certificatesResult.error
+ return;
+ }
+
+ const certificates = certificatesResult.value;
+ } catch (error) {
+ // Handle unexpected thrown errors
+ }Two exported error types have also changed:
DestroyErrorTypeis renamed toDestroyError.destroyalready returned aResult, andDestroyErroris now the fullMobileCredentialVerifierError<...>type rather than the error-type union alone.InitializeErrorTypeis replaced byInitializeErrorin the same way.
Update revocation status list method and type names
The revocation status list management API has been renamed from TrustedIssuer terminology to
Revocation terminology, to better reflect that these APIs manage the lists used to check the
revocation status of credentials.
| Previously | Now |
|---|---|
updateTrustedIssuerStatusLists() | refreshRevocationStatusLists() |
getTrustedIssuerStatusListsCacheInfo() | getRevocationStatusListsCacheInfo() |
UpdateTrustedIssuerStatusListsResult | RevocationStatusListsRefreshResult |
GetTrustedIssuerStatusListsCacheInfo | GetRevocationStatusListsCacheInfo |
None of the previous names are exported any more. Update your call sites:
- const cacheInfo = await getTrustedIssuerStatusListsCacheInfo();
+ const cacheInfoResult = await getRevocationStatusListsCacheInfo();
+
+ if (cacheInfoResult.isErr()) {
+ // Handle the error from cacheInfoResult.error
+ return;
+ }
- if (cacheInfo.nextUpdate && cacheInfo.nextUpdate.getTime() > Date.now()) {
+ if (cacheInfoResult.value.nextUpdate?.getTime() > Date.now()) {
// Status lists are still up to date
return;
}
- const refresh = await updateTrustedIssuerStatusLists();
- if (!refresh.success) {
- console.log(refresh.failedLists);
- }
+ const refreshResult = await refreshRevocationStatusLists();
+
+ if (refreshResult.isErr()) {
+ // Handle the error from refreshResult.error
+ return;
+ }
+
+ const refresh = refreshResult.value;
+
+ if (!refresh.isSuccess) {
+ // refresh is RevocationStatusListsRefreshFailure, so failedLists is guaranteed
+ console.log(refresh.failedLists);
+ }The nextUpdate field on RevocationStatusListsRefreshSuccess,
RevocationStatusListsRefreshFailure, and GetRevocationStatusListsCacheInfo has been narrowed from
Date | null | undefined to Date | undefined. Remove explicit null checks and use undefined
checks or optional chaining instead.
The example above also reflects the refresh result becoming a discriminated union, which is covered
in Narrow results on isSuccess.
Narrow results on isSuccess
OnlinePresentationSessionResult and RevocationStatusListsRefreshResult are now
isSuccess-discriminated unions instead of single objects with optional fields.
Online presentation results
The OnlinePresentationSessionResult returned by requestMobileCredentials and
AppleWallet.requestMobileCredentials is now discriminated on isSuccess:
- if (result.error) {
- console.log(result.error.message);
- } else {
- console.log(result.mobileCredentialResponse?.credentials);
- }
+ if (result.isSuccess) {
+ // result is OnlinePresentationSessionSuccess
+ console.log(result.mobileCredentialResponse?.credentials.length);
+ } else {
+ // result is OnlinePresentationSessionFailure, so error is guaranteed
+ console.log(result.error.message);
+ }OnlinePresentationSessionSuccesshasisSuccess: true,sessionId, an optionalchallenge, and an optionalmobileCredentialResponse. ThemobileCredentialResponseis absent when the verifier application is configured to deliver results over the back channel only, so the credentials are sent to your server rather than returned to the app.OnlinePresentationSessionFailurehasisSuccess: false,sessionId, an optionalchallenge, anderror. Theerrorfield is no longer optional.
Revocation status list refresh results
RevocationStatusListsRefreshResult is now discriminated on isSuccess, and the previous success
field has been removed. Replace result.success with result.isSuccess, and narrow before reading
failedLists, which is only present on failure results and is no longer optional when present. See
Update revocation status list method and type names
for a worked example.
Update verification result and response handling
MobileCredentialResponse.credentials and MobileCredentialResponse.credentialErrors are now
required arrays. They are always present, including as empty arrays when there are no items, so
optional chaining and null checks can be removed:
- if (response.credentials && response.credentials.length > 0) {
+ if (response.credentials.length > 0) {
// Handle the presented credentials
}VerificationResult is now a discriminated union on verified. When verified is false, reason
is required and always present. When verified is true, reason is not present, so narrow on
verified rather than optional chaining:
- if (!credential.verificationResult.verified && credential.verificationResult.reason) {
- console.log(credential.verificationResult.reason.type);
- }
+ if (!credential.verificationResult.verified) {
+ // verificationResult is narrowed, so reason is guaranteed
+ console.log(credential.verificationResult.reason.type);
+ }The per-credential claims and claimErrors fields on MobileCredentialPresentation remain
optional and are unchanged.
Handle new error codes
This release adds error codes across several enums, and adds a new enum. Adding these values is a
breaking change for exhaustive switch statements over these types.
MobileCredentialVerifierErrorType
InvalidLicense: the SDK license failed to validate or has expired.FailedToRegister: registering the app instance with MATTR VII failed.DeviceRequestValidationFailed: (iOS only) the device request is invalid.DataTransportDisconnected: (Android only) the data transport disconnected.InvalidDistributionUrl: a status list distribution URL could not be parsed.DistributionDownloadFailed: a status list distribution could not be downloaded.StatusListDownloadFailed: (Android only) a status list could not be downloaded.UnsupportedCurve: moved here fromProximityPresentationSessionErrorType.
ProximityPresentationSessionErrorType
RequestMobileCredentialOnTerminatedSession: a credential was requested on a session that has already terminated.DeviceRequestEncodingFailed: the device request could not be encoded.SessionEncryptionError: the session data could not be encrypted.MobileCredentialVerificationFailed: the presented credential could not be verified.
MobileCredentialVerifierReactNativeErrorType (new)
This new enum holds the error codes raised by the React Native SDK itself, rather than reported by the native SDK:
InvalidParams: the arguments passed to a function are missing or invalid. See Keep argument objects to documented fields.PlatformNotSupported: the operating system or platform does not support the requested operation. This code moved here fromMobileCredentialVerifierErrorType.
fetchAppleWalletConfiguration and handleDeepLink now return
MobileCredentialVerifierReactNativeErrorType, not MobileCredentialVerifierErrorType, when the
platform is unsupported.
RuntimeException may be thrown by any function
RuntimeException is the catch-all for an unexpected or unrecoverable failure in the SDK. Because
any function may throw or return it, it is not listed in each function's expected Result error
type. Handle it with your generic fallback strategy and report it to MATTR.
Update your error handling, logging, analytics, and support diagnostics to account for these new error codes.
Keep argument objects to documented fields
Invalid or malformed arguments are now rejected with an InvalidParams error code and a message
describing the offending field, instead of a synchronous Error with a message of the form
Invalid arguments for '<function>' function: .... Update any code that matched on the previous
message:
try {
await sendProximityPresentationRequest(options);
} catch (error) {
- if (error.message.startsWith("Invalid arguments for 'sendProximityPresentationRequest' function")) {
+ if ((error as RCTBridgeError).code === "InvalidParams") {
// Handle the invalid argument
}
}Android also now rejects unrecognized keys in argument objects. Any extra or misspelled field that is
not part of a function's documented options fails with an InvalidParams error. iOS ignores unknown
keys. Ensure argument objects contain only documented fields so behavior is consistent across
platforms:
const response = await sendProximityPresentationRequest({
mobileCredentialRequests: [mobileCredentialRequest],
checkStatus: true,
- skipStatusCheck: false,
});Update renamed and removed exports
| Export | Change |
|---|---|
SessionStatus | Renamed to SessionStatusErrorType. This is also the type of PresentationSessionTerminationError.sessionStatus. |
MobileCredentialVerifierErrorType.UnknownError | Renamed to RuntimeException. |
MobileCredentialVerifierErrorType.Connectivity | Renamed to ConnectivityError. |
MobileCredentialVerifierErrorType.SessionTimedOut | Renamed to SessionTimeOut. |
MobileCredentialVerifierErrorType.PlatformNotSupported | Moved to the new MobileCredentialVerifierReactNativeErrorType enum. |
ProximityPresentationSessionErrorType.UnsupportedCurve | Moved to MobileCredentialVerifierErrorType.UnsupportedCurve. |
ProximityPresentationSessionErrorType.TimeoutError | Removed. Use MobileCredentialVerifierErrorType.SessionTimeOut. |
ProximityPresentationSessionTerminationErrorType.Exception | Removed. Handle unexpected termination failures with your generic fallback strategy. |
OnlinePresentationResultErrorType.Unknown | Renamed to RuntimeException. |
DestroyErrorType | Renamed to DestroyError, and now the full error type rather than the error-type union. |
InitializeErrorType | Replaced by InitializeError, the full error type. |
Update your imports and type references:
- import { SessionStatus } from "@mattrglobal/mobile-credential-verifier-react-native";
+ import { SessionStatusErrorType } from "@mattrglobal/mobile-credential-verifier-react-native";
- if (error.type === MobileCredentialVerifierErrorType.UnknownError) {
+ if (error.type === MobileCredentialVerifierErrorType.RuntimeException) {These renames also change the error-type unions returned by:
createProximityPresentationSessionsendProximityPresentationRequestrequestMobileCredentialsfetchAppleWalletConfigurationhandleDeepLink
The SDK no longer validates its own arguments and return values with runtime schemas, so the following exports have been removed. They were implementation details of the bridge and are not replaced. Rely on the exported TypeScript types instead:
AppleWalletSchemaDateTimeValidatorDocTypeValidatorElementIDValidatorIntentToRetainValidatorMobileCredentialPresentationValidatorMobileCredentialRequestValidatorMobileCredentialResponseValidatorMobileCredentialResponseErrorCodeValidatorMobileCredentialStatusInfoValidatorNameSpaceValidatorTrustedIssuerCertificateValidator
Upgrade to React Native 0.83
The react-native peer dependency has been raised from >=0.81.x to >=0.83.x. Upgrade your
application to React Native 0.83 or later before installing this version. Refer to the
React Native upgrade helper for the
changes required in your project.
How would you rate this page?
Last updated on