light-mode-image
Learn
DC API

How to build a React Native application that can present a credential via the DC API

Digital Credentials (DC) API support is currently offered as a tech preview. The DC API specification itself is still under active development in the W3C Web Incubator CG, and platform implementations continue to evolve. As such, functionality may be limited, may not work in all scenarios, and could change or break without prior notice as browsers and operating systems update their implementations.

Overview

This guide demonstrates how to use the Holder SDK to build a React Native application that can present a claimed mDoc to a verifier remotely via the DC API.

The React Native Holder SDK wraps the native iOS and Android Holder SDKs, so the underlying behaviour matches the iOS guide (Annex C of ISO/IEC 18013-7:2025) and the Android guide (Annex D). The difference is that you enable and configure the feature from a single JavaScript initialize call, while some platform-specific native setup is still required, particularly on iOS.

Prerequisites

Application base

This guide builds on the knowledge gained in the Claim a credential and Remote presentation tutorials.

It is recommended to complete those tutorials first, then return here to add support for the DC API workflow.

Testing Devices

  • Mobile device:
    • An iOS device running iOS 26.0 or later, or an Android device running Android 14 or later.
    • The device must have a holder application with claimed credentials set up as per the Claim a credential tutorial and support for the DC API enabled as per the instructions in this guide.
  • Desktop device with a web browser that supports the DC API:
    • Chrome or a Chromium based browser v138 or later.
    • Safari v26 or later.

Development environment

  • For iOS, Xcode 26.0.0 or later is required to build the app extension described below.

How it works

The DC API is a browser standard that enables web applications to request and verify digital credentials directly from compatible wallet applications on the user's device. This provides a seamless user experience where credential presentation happens entirely within the browser context.

From a holder application point of view, there are several changes required to support remote presentations via the DC API compared to the standard OID4VP remote presentation workflow. The React Native Holder SDK exposes these through a single dcConfiguration option on initialize, which carries separate configuration for each platform:

  • On Android, enabling the DC API is handled entirely from JavaScript. When you set the Android configuration, the SDK registers all claimed credentials with the Digital Credentials Manager (DCM) and handles incoming presentation requests in the background.
  • On iOS, you configure the DC API from JavaScript (the app group and supported document types), but presentation requests are served by a native Identity Document Provider app extension. App extensions do not run in the React Native runtime, so this part must be implemented natively in Swift against the iOS Holder SDK.

Configuration provided for the platform you are not currently running on is ignored, so it is safe to supply both ios and android configuration in the same call.

Adjusting your application to support remote presentations via the DC API

You will make the following adjustments to enable the DC API in your application:

  1. Enable the DC API during SDK initialization.
  2. Complete the Android-specific setup.
  3. Complete the iOS-specific setup.
  4. Test the application.

Enable the DC API during SDK initialization

Enable DC API support by passing a dcConfiguration object to initialize. The object accepts platform-specific configuration under ios and android keys:

  • android.enabled: when true, all claimed credentials are enrolled with Android's Digital Credentials Manager (DCM) and made available for sharing.
  • ios.appGroup: an app group identifier accessible by both your app and its app extension. This must match the app group you configure in the iOS-specific setup below.
  • ios.supportedDocTypes: the document types your holder supports, as declared in your app's entitlements. These are provided via the SupportedDocType enum exported by the SDK.
Initializing the SDK with DC API support enabled
import MobileCredentialHolder, {
  SupportedDocType,
  UserAuthenticationBehavior,
} from "@mattrglobal/mobile-credential-holder-react-native";

const result = await MobileCredentialHolder.initialize({
  userAuthenticationConfiguration: {
    userAuthenticationBehavior: UserAuthenticationBehavior.OnDeviceKeyAccess,
  },
  dcConfiguration: {
    ios: {
      appGroup: "group.com.yourcompany.yourapp",
      supportedDocTypes: [
        SupportedDocType.mDL,
        SupportedDocType.photoid,
        SupportedDocType.eudi,
        SupportedDocType.euav,
        SupportedDocType.jpMnc,
      ],
    },
    android: {
      enabled: true,
    },
  },
});

if (result.isErr()) {
  // Handle initialization error
  console.error(result.error);
}

When you initialize the SDK with dcConfiguration:

  • All existing claimed credentials are registered for the DC API on the current platform.
  • Any future credentials issued to the holder are registered automatically.
  • On Android, the SDK is ready to handle incoming presentation requests in the background.
  • On iOS, the operating system recognizes your app extension as a valid provider for the configured document types (once the extension is set up as described below).

initialize must always be called from your React Native (JavaScript) code, which runs in your main application. On iOS, do not attempt to initialize the SDK from within the app extension — see the iOS-specific setup below.

Complete the Android-specific setup

On Android, setting android.enabled to true in dcConfiguration is all that is required to enable the DC API. The SDK registers your application as a credential provider, registers all claimed credentials with the Digital Credentials Manager, and handles incoming presentation requests and user authentication in the background — without any further involvement from your application.

Handle verifier authentication results (optional)

As with the native Android SDK, you can optionally detect whether the verifier can be trusted and require user confirmation accordingly. This is handled natively in your Android project (via intent filters in AndroidManifest.xml and your Android activity), not from JavaScript.

If you need this, follow the Handle verifier authentication results step in the Android guide. The intent filters, actions, and VerifierAuthenticationResult handling are identical for a React Native application, because they live in the native Android layer of your app.

If you do not implement this, the SDK still handles the presentation flow and user authentication with the operating system in the background.

Complete the iOS-specific setup

On iOS, presentation requests are served by a native Identity Document Provider app extension rather than your main application. Because app extensions do not run the React Native runtime, this extension must be implemented natively in Swift, using the iOS Holder SDK directly.

The JavaScript initialize call you set up above handles registering your credentials with the DC API. The remaining iOS work is native Xcode configuration and the extension itself, which is the same as for a native iOS application. Follow the iOS guide for the full walkthrough, and apply the React Native-specific notes below.

From the iOS guide, complete the following in your app's ios Xcode workspace:

  1. Configure your Xcode project to support the new app extension — set the deployment target, enable Keychain Sharing, add an App Group, and add the Digital Credentials provider entitlement.
  2. Create and configure an Identity Document Provider extension — add the extension target and give it the same Keychain Sharing group and App Group as the main app.
  3. Handle the presentation request in the app extension — implement the extension handler that creates the presentation session, shows the consent UI, and sends the response.

When applying those steps to a React Native project, note the following differences:

  • The App Group must match your JavaScript configuration. The app group you configure on the main app target and the extension target must exactly match the dcConfiguration.ios.appGroup value you passed to initialize in your React Native code. A common approach is to define the app group once as a Swift constant for the extension and pass the same string from JavaScript.

  • Initialize the SDK from React Native, not from the extension. Your main application initializes the SDK through the React Native initialize call, so you do not add the main-app initialization step from the iOS guide. The app extension does still call initializeAppExtension(appGroup:) (as shown in the iOS guide) so it can read the shared credential storage.

Do not call the SDK's initialize function from within the app extension. The SDK must only be initialized from your main application — in a React Native app this is your initialize call in JavaScript. The extension uses initializeAppExtension(appGroup:) instead. Calling initialize from the extension can overwrite storage keys and save them under an incorrect Keychain access group, causing initialization failures that are difficult to recover from.

  • Add the native iOS Holder SDK to the extension target. The extension imports MobileCredentialHolderSDK (the native iOS SDK) directly, as described in the iOS guide. This is separate from the @mattrglobal/mobile-credential-holder-react-native package your JavaScript code uses, and is added to the extension target via the framework or Swift Package Manager.

The presentation UI and handler code inside the extension are pure Swift and identical to the iOS guide — there is no React Native equivalent, because the extension runs outside the React Native runtime.

Test the application

Let's test that the application is working as expected in both workflows.

On iOS, run the app and then close it (this updates the app and its extension on your testing device) before testing.

Same-device workflow

  1. Use a browser on your testing mobile device to navigate to the MATTR Labs remote presentation testing tool.
  2. Select Digital Credentials API from the Select Experience list.
  3. Select Request credentials.
  4. Confirm interacting with the verifier on your mobile device when prompted by the operating system (this might look different based on the device and operating system version).
  5. Select the credential you wish to send to the verifier from the list suggested by the operating system.
  6. Send the response.
  7. The UI prompt will close, and you should see a successful verification indication in the browser where you initiated the request.

Cross-device workflow

  1. Use a desktop browser to navigate to the MATTR Labs remote presentation testing tool.
  2. Select Digital Credentials API from the Select Experience list.
  3. Select Request credentials.
  4. Open the camera on your testing device and scan the QR code.
    (On iOS, when using Safari and a device with the same Apple ID, the request is automatically transferred to the mobile device.)
  5. Confirm interacting with the verifier on your mobile device when prompted by the operating system (this might look different based on the device and operating system version).
  6. Select the credential you wish to send to the verifier from the list suggested by the operating system.
  7. Send the response.
  8. The UI prompt will close.
  9. Back on your desktop browser, you should see a successful verification indication.

Summary

You have just used the Holder SDK to build a React Native application that can present a claimed mDoc to a verifier remotely via the DC API.

This was achieved by making the following adjustments to your application:

  1. Enable the DC API during SDK initialization by passing a dcConfiguration.
  2. On Android, no further setup is required (verifier authentication handling is optional).
  3. On iOS, create and configure a native Identity Document Provider app extension to handle presentation requests.

What's next?

How would you rate this page?

Last updated on

On this page