React Native Holder SDK v10.0.0 Migration Guide
A comprehensive guide to migrating to React Native Holder 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 React Native Holder SDK v10.0.0, including breaking changes, new features, and migration steps.
This release focuses on strengthening trust at issuance, improving predictability in credential handling, and increasing consistency across platforms. It:
- Adds an optional SDK Backend, giving your app a connection to your MATTR VII tenant.
- Adds optional Wallet Attestation support, so issuers can verify wallet integrity.
- Adds support in the JavaScript/TypeScript layer to bridge the new platform configuration.
- Reshapes how the SDK reports failures, so expected error cases surface as typed values you can handle rather than as unrecognized thrown errors.
The SDK Backend (and Wallet Attestation, which builds on it) is optional in this release. You opt in by passing a platformConfiguration when initializing the SDK. If you omit it, the SDK skips registration and does not connect to a backend, so wallet attestation is unavailable, and existing integrations continue to work. We expect to make the SDK Backend required in an upcoming release, so we recommend adopting it now to prepare.
Key Features
- SDK Backend (optional): The React Native Holder SDK can now connect to a backend MATTR VII tenant, tying each SDK/app instance to your tenant. This allows you to view details about registered and active app instances directly from your tenant for operational insights. The SDK Backend also establishes a remote management channel that we expect to expand soon with additional features, such as remote syncing of trusted issuer lists and eventing. The SDK Backend is enabled by providing a
platformConfigurationat initialization. - Wallet Attestation support (optional): Building on the SDK Backend channel, the React Native Holder SDK now supports Wallet Attestation, allowing your holder application to prove to issuers that it is a trusted wallet before credentials are issued. When an issuer requires it, the SDK uses the SDK Backend connection to obtain wallet attestation tokens from your MATTR VII tenant. Wallet Attestation requires an SDK Backend to be configured.
- Stronger application identity during issuance: Pre-authorized credential issuance flows now pass the application's
client_id, ensuring the holder is accurately represented when interacting with issuers. This improves compatibility with issuers applying stricter controls. - More predictable credential retrieval results: Credential retrieval responses are now more structured and deterministic, explicitly identifying success or failure with guaranteed fields per result type.
- Typed, handleable errors: Seven functions that previously resolved a plain value now return a
Result, and many failures that previously surfaced as unrecognized thrown errors are now typed error codes. The same error codes are raised on both iOS and Android. - Cross-platform alignment: Naming and authentication types have been aligned across the iOS and Android Holder SDKs, minimizing divergence for teams maintaining cross-platform applications.
- 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 | Seven functions now return a Result: deleteCredential, destroy, deleteTrustedVerifierCertificate, getCredentials, getTrustedIssuerCertificates, getTrustedVerifierCertificates, and getCurrentProximityPresentationSession | Handle the Result instead of using the resolved value directly. These functions can still throw, so keep a try/catch alongside the Result handling. |
| 2 | RetrieveCredentialsResponse items are now isSuccess-discriminated unions instead of a single object with optional fields | Narrow on isSuccess and remove checks for the previously optional credentialId and error fields. |
| 3 | doctype renamed to docType | Rename all usages of doctype to docType on credential retrieval result items and on OfferedCredential. |
| 4 | MobileCredentialAuthenticationOption renamed to DeviceAuthenticationOption, and the mobileCredentialAuthenticationOption option on createProximityPresentationSession renamed to deviceAuthenticationOption | Update all imports, type references, and the option passed to createProximityPresentationSession. Neither previous name is exported any more. On Android, passing the old option name now fails with an InvalidParams error. |
| 5 | DeviceKeyAuthenticationType removed in favor of UserAuthenticationType | Replace every DeviceKeyAuthenticationType reference, including the type field of DeviceKeyAuthenticationPolicy, with UserAuthenticationType. |
| 6 | UserAuthenticationType values have changed. BiometricOnly is replaced by BiometryCurrentSet, BiometricOrPasscode is replaced by UserPresence, and the default is now UserPresence | Update the userAuthenticationType field of userAuthenticationConfiguration. This field is no longer iOS only, so review its effect on Android. initialize may now return UserAuthenticationNotSupported on Android when BiometryCurrentSet is combined with a userAuthenticationBehavior of OnInitialize. |
| 7 | DeprecatedDeviceKeyAuthenticationType removed | Replace references with the modern equivalent. Existing device keys are now reported as BiometryCurrentSet instead of BiometricOnly, and as UserPresence instead of BiometricOrPasscode. |
| 8 | VerificationResult failure detail moved from reason to failureType, and VerificationFailedReason was removed | Rename .reason to .failureType and remove any use of VerificationFailedReason. The { type, message } value shape is unchanged. |
| 9 | 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. |
| 10 | 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. |
| 11 | OfferedCredential.claims is now optional | Handle the case where claims is absent rather than assuming an array is always present. |
| 12 | Credentials whose issuer signed data contains no namespaces, or a namespace with no claims, are now rejected | Handle the decoding error where credentials are retrieved or added. MobileCredential.claims and MobileCredentialMetadata.claims are now guaranteed to be populated. |
| 13 | Pre-authorized issuance now sends the application client_id instead of a default identifier | Ensure your application has a valid configured client_id and that your issuers recognize it. |
| 14 | Renamed and removed exports: SessionStatus, DateTime, NativeRetrieveCredentialsResponse, MobileCredentialHolderErrorType.ExistingProximityPresentationSessionNotFound, ProximityPresentationSessionTerminationErrorType.Exception, and RetrieveCredentialsErrorTypes.UserAuthentication | Update imports, type references, and error handling. See Update renamed and removed exports. |
| 15 | RetrieveCredentialsErrorTypes.UserAuthenticationFailed now has the value "UserAuthentication", previously "UserAuthenticationFailed" | Update any code that compares the raw error string rather than the enum member. |
| 16 | AuthorizationResponseJWECreationFailed removed from the sendOnlinePresentationResponse error type, and UserAuthenticationUnrecoverableKey removed from the sendProximityPresentationResponse error type | Remove handling for these two cases. They are no longer raised. |
| 17 | New error codes added to MobileCredentialHolderErrorType and ProximityPresentationSessionErrorType, plus a new MobileCredentialHolderReactNativeErrorType enum | Update exhaustive switch statements over these error types. See Handle new error codes. |
| 18 | The internal storage location for iOS app extension logs has changed | No code change required, the same getCurrentLogFilePath call and appGroup option are used, but app extension logs written before the upgrade become inaccessible. See Known Issues. |
SDK initialization does not require platform/tenant configuration in this release. The
platformConfiguration option is optional. Provide it only if you want to configure the SDK Backend
and Wallet Attestation. See Configure the SDK Backend at initialization.
Migration Steps
(Optional) Create Holder Applications on your MATTR VII tenant
The SDK Backend is optional in this release. If you do not need it, you can skip this step and the next one. The SDK continues to function without a platformConfiguration.
To configure the SDK Backend, the React Native Holder SDK connects to a MATTR VII tenant via the underlying native SDKs. This connection gives you access to a centralized view of registered and active app instances in MATTR VII, the optional Wallet Attestation feature, and other centralized management capabilities we plan to deliver over this channel.
We expect the SDK Backend to become required in an upcoming release. We recommend adopting it now to prepare, even if you do not yet use Wallet Attestation.
Since React Native targets both iOS and Android, you need to create two Holder Applications, one for each platform target. A Holder Application is bound to platform-specific identifiers, so a single application cannot cover both targets. Use the same Client ID for both, so issuers see one wallet identity regardless of the platform your app runs on.
Create the iOS Holder Application
- Log in to the MATTR Portal and expand the Credential holding 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 Holder Application (iOS). - Use the Client ID text box to insert the OAuth 2.0
client_idthat identifies your wallet application. This value is included in attestation JWTs and must match theclient_idconfigured on the issuer's Authorization Server. Refer to agreeing on a client identifier for more information. - Use the Type radio button to select iOS.
- Use the Team ID field to insert your Apple Developer Team ID.
- Use the Bundle ID field to insert the Bundle ID of your iOS app (must match your Xcode project configuration).
- Use the App Attest toggle to set whether App Attest is Active or Inactive, and, when active, use the App Attest environment toggle to select Development or Production. When active, the app instance must provide a valid App Attest attestation during registration and token renewal. When inactive, the app can register and renew tokens using an authentication assertion only. Refer to attestation vs assertion fall back for more information.
- Use the Max time offline field to set the maximum time the SDK can operate offline before requiring a new license token. The minimum is 1 day and the maximum is 30 days. The default is 7 days. Refer to token validity and offline use 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 iOS target when initializing the SDK.
Create the Android Holder Application
- Return to Applications in the Credential holding 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 Holder Application (Android). - Use the Client ID text box to insert the same OAuth 2.0
client_idyou used for the iOS Holder Application. - Use the Type radio button to select Android.
- Use the Package name field 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. This ensures the tenant only accepts requests from known and trusted applications. Refer to Android app signing for more information.
- Use the Key Attestation toggle to set whether Key Attestation is Active or Inactive. When active, the app instance must provide a valid Key Attestation during registration and token renewal. When inactive, the app can register and renew tokens using an authentication assertion only. Refer to attestation vs assertion fall back for more information.
- Use the Max time offline field to set the maximum time the SDK can operate offline before requiring a new license token. The minimum is 1 day and the maximum is 30 days. The default is 7 days. Refer to token validity and offline use 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.
Once both Holder Applications are created, your application is able to use the SDK Backend and interact with the MATTR VII platform, for example to obtain attestation tokens.
Prefer the API? You can create each Holder Application with a POST /v1/holder/applications request instead. See the SDK Backend guide for the full API request and field reference.
The clientId you configure here is the same value you must:
- Pass as the
clientIdin the options when callingretrieveCredentials. - Register with each issuer you intend to interact with, so the issuer can identify and trust requests coming from your wallet application.
(Optional) Configure the SDK Backend at initialization
To configure the SDK Backend, pass a platformConfiguration through the JS/TS layer into the native SDKs when initializing. This option is optional. Omit it to initialize the SDK without an SDK Backend.
Since React Native bridges both iOS and Android, and each platform has its own Holder Application registered on your MATTR VII tenant (see the previous step), your initialization code must pass the correct platform-specific applicationId at runtime. Use Platform.OS to select the appropriate value:
import { initialize } from "@mattrglobal/mobile-credential-holder-react-native";
+ import { Platform } from "react-native";
- await initialize({ instanceId: "your-instance-id" });
+ const applicationId =
+ Platform.OS === "android"
+ ? "your-android-holder-application-id"
+ : "your-ios-holder-application-id";
+
+ await initialize({
+ instanceId: "your-instance-id",
+ platformConfiguration: {
+ tenantHost: "https://your-tenant.vii.mattr.global",
+ applicationId,
+ },
+ });tenantHost: The URL of your MATTR VII tenant. This must be the tenant where your Holder Applications are configured.applicationId: Theidof the Holder Application that matches the current platform target.
Replace the placeholder values with the ID recorded when you created each Holder Application. In practice, you would typically store these values in a configuration file or environment variables. When platformConfiguration is omitted, the SDK skips registration and does not connect to a backend, and wallet attestation is not available.
Confirm that:
- The
applicationIdused on iOS corresponds to the Holder Application created with your app's Bundle ID and Team ID. - The
applicationIdused on Android corresponds to the Holder Application created with your app's package name and signing certificate thumbprints. - Environment-specific tenant URLs are correctly configured.
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, regardless of whether you configure the SDK Backend.
MobileCredentialHolderErrorType
Eight error codes that were previously declared only as per-function string literals are now members of the enum: FailedToRetrieveCredentials, FailedToDiscoverCredentialOffer, FailedToCreateAuthorizationSession, RedirectUriNotFound, InvalidTransactionCode, WebAuthenticationFailed, UnsupportedDeviceKeyAuthenticationPolicy, and InvalidCredentialOffer. Their values are unchanged, and the per-function enums that reference them (DiscoverCredentialOfferErrorType, CreateAuthorizationSessionErrorType, and RetrieveCredentialsErrorTypes) keep the same values.
The following members are new:
StorageInitialization: storage could not be initialized for the SDK.SdkNotInitialized: the SDK has not been initialized.DeviceKeyGenerationError: a device key could not be generated.DeviceKeyNotDeleted: a device key could not be deleted from storage.InvalidCertificate: a supplied certificate is not valid.ClientMetadataServiceError: verifier client metadata could not be resolved during an online presentation.ResponseModeNotSupported: the authorization request asked for an unsupported response mode.FailedToCreateProximityPresentationSession: a proximity presentation session could not be created.NfcDeviceEngagementNotFound: a proximity session was started withengagementFromNfcbut no NFC device engagement was available.ActivityRequired: an Android activity is required to complete the operation.InvalidDeviceKeyAuthenticationPolicy: the supplied device key authentication policy is not valid.DeviceKeyAuthenticationPolicyChangedException: the authentication policy of an existing device key has changed.UserAuthenticationInvalidatedByBiometricEnrollment: the device key was invalidated because the biometrics enrolled on the device changed.UserAuthenticationNotSupported: the requested user authentication configuration is not supported on this device.MACAuthenticationUnavailableForAuthenticationPolicy: MAC authentication cannot be used with the credential's authentication policy.CalledFromAppExtension: an API that is unavailable in app extensions was called from an iOS app extension.OperationFailed: the operation failed for a platform-specific reason described in the error message.RuntimeException: an unexpected or unrecoverable failure in the SDK.
ProximityPresentationSessionErrorType
ResponseNotCreated: the response to send to the verifier could not be created.ResponseEncryptionFailed: the response could not be encrypted.SessionDecryption: the device request could not be decrypted.PresentationNotCreated: the credential presentation could not be created.
MobileCredentialHolderReactNativeErrorType (new)
This new enum holds the error codes raised by the React Native SDK itself, rather than reported by the device platform:
InvalidParams: the arguments passed to a function are missing or invalid. This code is thrown rather than returned in aResult, so read it from thecodefield of the caught error. See Keep argument objects to documented fields.ExistingProximityPresentationSessionNotFound: there is no active proximity presentation session. This code moved here fromMobileCredentialHolderErrorType.
SDK Backend errors
initialize may now return two errors related to the SDK Backend:
InvalidLicense: the SDK license failed to validate or has expired.FailedToRegister: registering the app instance with MATTR VII failed.
InvalidLicense may also be returned by most public APIs when an SDK Backend is configured but a valid license is not present. This includes addCredential, getCredential, getCredentials, deleteCredential, generateDeviceKey, discoverCredentialOffer, createAuthorizationSession, retrieveCredentials, retrieveCredentialsUsingAuthorizationSession, createOnlinePresentationSession, createProximityPresentationSession, sendProximityPresentationResponse, getCurrentProximityPresentationSession, addTrustedIssuerCertificates, getTrustedIssuerCertificates, deleteTrustedIssuerCertificate, addTrustedVerifierCertificates, getTrustedVerifierCertificates, and deleteTrustedVerifierCertificate.
Wallet Attestation errors
retrieveCredentials and retrieveCredentialsUsingAuthorizationSession may now return two errors related to Wallet Attestation:
InvalidCredentialOffer: the offer requires attestation but noplatformConfigurationwas provided, or the SDK supports none of the authorization server's advertised client authentication methods.InvalidWalletAttestation: the authorization server rejected the attestation token.
When attestation fails for an individual credential, that credential's RetrieveCredentialFailure carries an invalidWalletAttestation error. Wallet attestation errors only occur when an SDK Backend is configured and an issuer requires attestation.
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 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.
Update client_id configuration
Previously, the client_id passed to
retrieveCredentials
was not shared with the issuer during the pre-authorized code flow, so any value would work. This is no longer the case. The SDK now presents the client_id to the issuer as part of wallet attestation, and the issuer validates it against its list of trusted wallet providers.
To prepare for this change:
- Coordinate with the issuer to register your wallet application as a trusted wallet provider. The issuer will provide you with a
client_idthat identifies your application. Refer to agreeing on a client identifier for more information. - Pass the issuer-provided
client_idin the options when callingretrieveCredentials.
const result = await retrieveCredentials({
credentialOffer: offer,
- clientId: "any-value",
+ clientId: "issuer-provided-client-id",
});Issuance flows that previously worked with an arbitrary client_id will fail if the issuer requires a trusted wallet provider. Ensure you have coordinated with each issuer and obtained the correct client_id before upgrading. Test direct issuance flows to confirm credentials are issued successfully.
Handle the new Result returns
Seven functions that previously resolved a plain value now return a neverthrow Result, so their expected error cases surface as typed values you can handle. Callers must handle the Result instead of using the resolved value directly. These functions can still throw, so a try/catch is still required alongside handling the Result.
| Function | Previously | Now |
|---|---|---|
deleteCredential | Promise<void> | Promise<Result<void, DeleteCredentialError>> |
destroy | Promise<void> | Promise<Result<void, DestroyError>> |
deleteTrustedVerifierCertificate | Promise<void> | Promise<Result<void, DeleteTrustedVerifierCertificateError>> |
getCredentials | Promise<MobileCredentialMetadata[]> | Promise<Result<MobileCredentialMetadata[], GetCredentialsError>> |
getTrustedIssuerCertificates | Promise<TrustedIssuerCertificate[]> | Promise<Result<TrustedIssuerCertificate[], GetTrustedIssuerCertificatesError>> |
getTrustedVerifierCertificates | Promise<TrustedVerifierCertificate[]> | Promise<Result<TrustedVerifierCertificate[], GetTrustedVerifierCertificatesError>> |
getCurrentProximityPresentationSession | Promise<ProximityPresentationSession | undefined> | Promise<Result<ProximityPresentationSession | undefined, GetCurrentProximityPresentationSessionError>> |
The matching error types are now exported from the package: DeleteCredentialError, DestroyError, DeleteTrustedVerifierCertificateError, GetCredentialsError, GetTrustedIssuerCertificatesError, GetTrustedVerifierCertificatesError, and GetCurrentProximityPresentationSessionError.
Update each call site to handle the Result:
- const credentials = await getCredentials();
+ try {
+ const getCredentialsResult = await getCredentials();
+
+ if (getCredentialsResult.isErr()) {
+ // Handle the error from getCredentialsResult.error
+ return;
+ }
+
+ const credentials = getCredentialsResult.value;
+ } catch (error) {
+ // Handle unexpected thrown errors
+ }Refer to each function's @throws annotation for the errors it can throw, and to RuntimeException may be thrown by any function.
Functions that already returned a Result, such as initialize and retrieveCredentials, are unchanged. isInitialized and terminateProximityPresentationSession still resolve plain values and are also unchanged.
Update credential retrieval result handling
RetrieveCredentialsResponse has changed from an array of flat objects with optional fields to an array of RetrieveCredentialItem, a discriminated union with isSuccess as the discriminator. Each item is either a RetrieveCredentialSuccess (with isSuccess: true, docType, and credentialId) or a RetrieveCredentialFailure (with isSuccess: false, docType, and error). TypeScript enforces which fields are available after narrowing.
Update your result iteration logic to narrow on isSuccess:
const result = await retrieveCredentials(options);
if (result.isOk()) {
for (const item of result.value) {
- if (item.credentialId) {
- // Use item.doctype and item.credentialId
- console.log(item.credentialId);
+ if (item.isSuccess) {
+ // item is RetrieveCredentialSuccess, so credentialId is guaranteed
+ console.log(item.credentialId);
} else {
- // Use item.doctype and item.error
- console.log(item.error?.message);
+ // item is RetrieveCredentialFailure, so error is guaranteed
+ console.log(item.error.message);
}
}
}- The
errorfield is no longer optional. It is always present on failure items and never present on success items. - The
credentialIdfield is no longer optional. It is always present on success items and never present on failure items.
Update TypeScript type guards, tests, and any downstream logic that checked for optional fields.
Rename doctype to docType
The doctype field has been renamed to docType (camelCase) to align naming across iOS and Android. This affects credential retrieval result items and
OfferedCredential
returned by discoverCredentialOffer.
Update all references from .doctype to .docType:
- const documentType = credential.doctype;
+ const documentType = credential.docType;Rename MobileCredentialAuthenticationOption to DeviceAuthenticationOption
MobileCredentialAuthenticationOption has been renamed to DeviceAuthenticationOption, aligning naming with the native Holder SDKs, which made the same rename in iOS 6.0.0 and Android 7.0.0. The Signature and Mac values are unchanged.
Update all imports and type references, and rename the mobileCredentialAuthenticationOption option on createProximityPresentationSession to deviceAuthenticationOption:
- import { MobileCredentialAuthenticationOption } from "@mattrglobal/mobile-credential-holder-react-native";
+ import { DeviceAuthenticationOption } from "@mattrglobal/mobile-credential-holder-react-native";
- const authOption: MobileCredentialAuthenticationOption = MobileCredentialAuthenticationOption.Mac;
+ const authOption: DeviceAuthenticationOption = DeviceAuthenticationOption.Mac;
await createProximityPresentationSession({
onRequestReceived,
- mobileCredentialAuthenticationOption: authOption,
+ deviceAuthenticationOption: authOption,
});Neither previous name is exported any more. On Android, passing the old mobileCredentialAuthenticationOption key fails with an InvalidParams error rather than being ignored, as described in Keep argument objects to documented fields. On iOS the key is ignored and the default authentication option is used.
Migrate DeviceKeyAuthenticationType to UserAuthenticationType
The DeviceKeyAuthenticationType enum export has been removed. Use UserAuthenticationType instead, which now carries the same values:
NoneUserPresenceBiometryAnyBiometryCurrentSetDeviceCredential
Update all references, including the type field of the DeviceKeyAuthenticationPolicy passed to generateDeviceKey, retrieveCredentials, and retrieveCredentialsUsingAuthorizationSession:
- import { DeviceKeyAuthenticationType } from "@mattrglobal/mobile-credential-holder-react-native";
+ import { UserAuthenticationType } from "@mattrglobal/mobile-credential-holder-react-native";
const result = await generateDeviceKey({
issuer,
audience,
- authenticationPolicy: { type: DeviceKeyAuthenticationType.BiometryCurrentSet },
+ authenticationPolicy: { type: UserAuthenticationType.BiometryCurrentSet },
});The DeprecatedDeviceKeyAuthenticationType enum, and its BiometricOnly and BiometricOrPasscode values, has also been removed. A device key that was previously associated with a deprecated type is now reported as its modern equivalent, so update any code that reads DeviceKeyAuthenticationInfo.type:
- case DeprecatedDeviceKeyAuthenticationType.BiometricOnly:
+ case UserAuthenticationType.BiometryCurrentSet:
- case DeprecatedDeviceKeyAuthenticationType.BiometricOrPasscode:
+ case UserAuthenticationType.UserPresence:Update userAuthenticationType at initialization
UserAuthenticationType is also used for the userAuthenticationType field of the userAuthenticationConfiguration passed to initialize. It previously carried only BiometricOnly and BiometricOrPasscode. It now carries the same values used for device key authentication policies:
NoneUserPresence, which replacesBiometricOrPasscodeBiometryAnyBiometryCurrentSet, which replacesBiometricOnlyDeviceCredential
The default for userAuthenticationType is now UserPresence, previously BiometricOrPasscode.
await initialize({
userAuthenticationConfiguration: {
userAuthenticationBehavior: UserAuthenticationBehavior.OnDeviceKeyAccess,
- userAuthenticationType: UserAuthenticationType.BiometricOrPasscode,
+ userAuthenticationType: UserAuthenticationType.UserPresence,
},
});userAuthenticationType is no longer iOS only, so review the effect of your configuration on Android as well. initialize may now return UserAuthenticationNotSupported on Android when BiometryCurrentSet is combined with a userAuthenticationBehavior of OnInitialize.
Update VerificationResult failure handling
On a failed verification, the failure detail has moved from a reason property to failureType, and the VerificationFailedReason type has been removed. The { type, message } value shape is unchanged.
if (!credential.verificationResult.verified) {
- console.log(credential.verificationResult.reason.type);
+ console.log(credential.verificationResult.failureType.type);
}Rename every .reason access on a VerificationResult to .failureType, and remove any use of VerificationFailedReason from your type annotations and downstream mapping logic.
Handle optional OfferedCredential.claims
claims on OfferedCredential (returned in credentials from discoverCredentialOffer) is now optional and is only present for offers that contain claim data. This aligns with the OID4VCI 1.0 specification.
Handle the case where claims is absent rather than assuming an array is always present:
- for (const claim of offeredCredential.claims) {
- // Use the claim
- }
+ // claims may be undefined when the offer contains no claim data
+ for (const claim of offeredCredential.claims ?? []) {
+ // Use the claim
+ }Handle credentials with empty claims
Retrieving or adding a credential whose issuer signed data contains no namespaces, or a namespace with no claims, now fails with a decoding error instead of producing a credential with empty claims.
This guarantees that MobileCredential.claims and MobileCredentialMetadata.claims are always populated, so you can remove defensive checks for empty claim data. Handle the error where credentials are retrieved or added, and check the per-credential error on any RetrieveCredentialFailure item.
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 addCredential(options);
} catch (error) {
- if (error.message.startsWith("Invalid arguments for 'addCredential' 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 credential = await getCredential(credentialId, {
fetchUpdatedStatusList: false,
- skipStatusCheck: true,
});Update renamed and removed exports
| Export | Change |
|---|---|
SessionStatus | Renamed to SessionStatusErrorType. This is also the type of PresentationSessionTerminationError.sessionStatus. |
DateTime | Removed. The validFrom, validUntil, expectedUpdate, and signed fields of ValidityInfo are now typed as Date. |
NativeRetrieveCredentialsResponse | Removed. Use RetrieveCredentialsResponse, or the RetrieveCredentialItem, RetrieveCredentialSuccess, and RetrieveCredentialFailure types. |
MobileCredentialHolderErrorType.ExistingProximityPresentationSessionNotFound | Moved to the new MobileCredentialHolderReactNativeErrorType enum, which holds the error codes raised by the SDK itself rather than reported by the device platform. |
ProximityPresentationSessionTerminationErrorType.Exception | Removed. Handle unexpected presentation failures with your generic fallback strategy. |
RetrieveCredentialsErrorTypes.UserAuthentication | Removed. Use RetrieveCredentialsErrorTypes.UserAuthenticationFailed. |
Update your imports and type references:
- import { SessionStatus, DateTime } from "@mattrglobal/mobile-credential-holder-react-native";
+ import { SessionStatusErrorType } from "@mattrglobal/mobile-credential-holder-react-native";
- const validFrom: DateTime = credential.validityInfo.validFrom;
+ const validFrom: Date = credential.validityInfo.validFrom;RetrieveCredentialsErrorTypes.UserAuthenticationFailed now has the value "UserAuthentication", previously "UserAuthenticationFailed". Code that compares the enum member is unaffected. Code that compares the raw error string must be updated, and we recommend switching to the enum member:
if (result.isErr()) {
- if (result.error.type === "UserAuthenticationFailed") {
+ if (result.error.type === RetrieveCredentialsErrorTypes.UserAuthenticationFailed) {
// Handle the failed user authentication
}
}Two errors are no longer raised and have been removed from the error types they appeared in, so you can remove their handling:
sendOnlinePresentationResponseno longer returnsAuthorizationResponseJWECreationFailed.sendProximityPresentationResponseno longer returnsUserAuthenticationUnrecoverableKey.
Known Issues
- If your app includes its own iOS app extension, the internal storage location for iOS app extension logs has changed. Logs are still retrieved with the same
getCurrentLogFilePathcall andappGroupoption, so no code change is required. However, any app extension logs written before upgrading, up to the 48 hour retention window, are no longer accessible after the upgrade. The location for main SDK logs is unchanged. Refer to SDK logging for more information.
How would you rate this page?
Last updated on