npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@animo-id/expo-digital-credentials-api

v0.4.0

Published

Expo wrapper around Android Digital Credentials API

Readme


An Expo Module to automatically set up and configure Digital Credentials API for Android in Expo apps.

  • Currently two default matcher implementations for matching credentials based on a request is bundled, which only supports mdoc, dc+sd-jwt, openid4vp , dcql, signed requests and unsigned requests. In the future support for a custom matcher might be added.
  • During development when the activity is launched and the application is already running this results in render errors. In production these errors won't occur, but it does hinder the development experience. We're still looking for a solution.
  • This library is tested with Expo 52 and React Native 0.76. It uses some hacks to use Kotlin 2.0.21, and is likely to break in non-default application setups. React Native 77 will use Kotlin 2 by default, and these hacks shouldn't be needed anymore.
  • When using the CMWallet matcher, icons provided for credentials are not rendered.

[!NOTE]
This library integrates with experimental Android APIs, as well as draft versions of several specifications. Expect all APIs to break in future releases.

Getting Started

Install the module using the following command.

# yarn
yarn add @animo-id/expo-digital-credentials-api

# npm
npm install @animo-id/expo-digital-credentials-api

# npm
pnpm install @animo-id/expo-digital-credentials-api

Then prebuild the application so the Expo Module wrapper can be added as native dependency (If you aren't making any manual modification to the Android directories you can add them to the gitignore of your project and generate them on demand):

# yarn
yarn expo prebuild

# npm
npx expo prebuild

That's it, you now have the Digital Credentials API configured for your Android project.

[!WARNING]
You might need to set the Kotlin version of your project to 2.0.21. To do this, add the expo-build-properties dependency to your project, and configure it with android.kotlinVersion set to '2.0.21'.

[
  "expo-build-properties",
  {
    "android": {
      "kotlinVersion": "2.0.21"
    }
  }
]

Usage

You can now import @animo-id/expo-digital-credentials-api in your application.

Registering Credentials

To make Android aware of the credentials availble in your wallet, you need to register the credentials. Every time the credentials in your application changes, you should call this method again.

When registering credentials you can also choose the matcher that is used. When registering credentials with a new matcher the old matcher will not be used anymore (the latest register call always overrides previous calls). The supported matchers are:

  • CMWallet matcher taken from https://github.com/digitalcredentialsdev/CMWallet. (current version)
    • Supports SD-JWT VC and mDOC
    • Supports signed requests
    • Does not support icons
    • Does not support showing claim values
  • Ubique matcher taken from https://github.com/UbiqueInnovkation/oid4vp-wasm-matcher. (current version).
    • Supports SD-JWT VC and mDOC
    • Supports signed requests
    • Supports icons
    • Supports showing claim values
import {
  registerCredentials,
  RegisterCredentialsOptions,
} from "@animo-id/expo-digital-credentials-api";

// See RegisterCredentialsOptions for all options
await registerCredentials({
  matcher: "cmwallet",
  credentials: [
    {
      id: "1",
      display: {
        title: "Drivers License",
        subtitle: "Issued by Utopia",
        claims: [
          {
            path: ["org.iso.18013.5.1", "family_name"],
            displayName: "Family Name",
          },
        ],
        iconDataUrl:
          "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAaUlEQVR4nOzPUQkAIQDA0OMwpxksY19D+PEQ9hJsY6/5vezXAbca0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0E4AAAD//7vSAeZjAN7dAAAAAElFTkSuQmCC",
      },
      credential: {
        doctype: "org.iso.18013.5.1.mDL",
        format: "mso_mdoc",
        namespaces: {
          "org.iso.18013.5.1": {
            family_name: "Glastra",
          },
        },
      },
    },
    {
      id: "2",
      display: {
        title: "PID",
        subtitle: "Issued by Utopia",
        claims: [
          {
            path: ["first_name"],
            displayName: "First Name",
          },
          {
            path: ["address", "city"],
            displayName: "Resident City",
          },
        ],
        iconDataUrl:
          "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAaUlEQVR4nOzPUQkAIQDA0OMwpxksY19D+PEQ9hJsY6/5vezXAbca0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0BrQGtAa0E4AAAD//7vSAeZjAN7dAAAAAElFTkSuQmCC",
      },
      credential: {
        vct: "eu.europa.ec.eudi.pid.1",
        format: "dc+sd-jwt",
        claims: {
          first_name: "Timo",
          address: {
            city: "Somewhere",
          },
        },
      },
    },
  ],
} satisfies RegisterCredentialsOptions);

Handling Credential Request

When the user has selected a credential from your application, the application will be launched with an intent to retrieve the credentials. A custom component will be used and rendered as an overlay.

Registering the component

You should register the component as early as possible, usually in your index.ts file. If you're using Expo Router, follow these steps to setup a custom entry point.

The component will be rendered in a full screen window, but with a transparent background. This allows you to render an overlay rather than a full screen application. By default all screen content that you do not render something over, has an onPress handler and will abort the request. You can disable this by setting cancelOnPressBackground to false.

import { registerRootComponent } from "expo";

import App from "./App";
import { MyCustomComponent } from "./MyCustomComponent";

// import the component registration method
// make sure to import this from the /register path
// so it doesn't load the native module yet, as that will prevent the app from correctly loading
import registerGetCredentialComponent from "@animo-id/expo-digital-credentials-api/register";

// Registers the componetn to be used for sharing credentials
registerGetCredentialComponent(MyCustomComponent);

// Default expo method call
registerRootComponent(App);

Handling the request

The request is passed to the registered component as request and has type DigitalCredentialsRequest.

import {
  type DigitalCredentialsRequest,
  sendErrorResponse,
  sendResponse,
} from "@animo-id/expo-digital-credentials-api";
import { Button } from "react-native";
import { Text, View } from "react-native";

export function MyCustomComponent({
  request,
}: {
  request: DigitalCredentialsRequest;
}) {
  return (
    <View style={{ width: "100%" }}>
      <Button
        title="Send Response"
        onPress={() =>
          sendResponse({ response: JSON.stringify({ vp_token: "something" }) })
        }
      />
      <Button
        title="Send Error Response"
        onPress={() =>
          sendErrorResponse({ errorMessage: "Send error response" })
        }
      />
    </View>
  );
}

Note on Expo Router

If you're using Expo Router, the root application is automatically loaded and executed, even if a custom activity is launched in React Native, and thus your main application logic will be executed (although not visible).

To prevent this from happening, you can create a small wrapper that returns null when the current activity is the get credential activitiy using the isGetCredentialActivity method. Make sure to only call this method once your app component is loaded, to prevent the app loading to get stuck.

import { isGetCredentialActivity } from "@animo-id/expo-digital-credentials-api";

export default function App() {
  const isDcApi = useMemo(() => isGetCredentialActivity(), []);
  if (isDcApi) return null;

  return <MainApp />;
}

Contributing

Is there something you'd like to fix or add? Great, we love community contributions! To get involved, please follow our contribution guidelines.

License

Expo Digital Credentials Api is licensed under the Apache 2.0 license.