Credential Holder API

The Credential Holder API enables Android apps to manage and present digital credentials to verifiers.

Get started

To use the Credential Holder API, add the following dependencies to your app module's build script:

// In your app module's build.gradle:
dependencies {
    implementation(libs.androidx.registry.provider)
    implementation(libs.androidx.registry.provider.play.services)
}

// In libs.versions.toml:
registryDigitalCredentials = "1.0.0-alpha01"

androidx-registry-provider = { module = "androidx.credentials.registry:registry-provider", version.ref = "registryDigitalCredentials" }
androidx-registry-provider-play-services = { module = "androidx.credentials.registry:registry-provider-play-services", version.ref = "registryDigitalCredentials" }

Register credentials with Credential Manager

A wallet needs to register credential metadata so Credential Manager can filter and display them in the credential selector when a request comes in.

Image showing the digital credentials UI in Credential Manager
Figure 1. The digital credentials UI.

The Credential Manager Selector UI

The format for this metadata is passed into a RegisterCredentialsRequest. Create a [RegistryManager][1] and register the credentials:

In this example, the metadata is compiled from a database of credentials entries. You can find a reference in our sample wallet which registers the metadata on app load. In the future, credential database composition will be supported by the Jetpack API. At that point, you can register the credential metadata as well-defined data structures.

The registry persists across device reboots. Re-registering the same registry of the same ID + type will overwrite the previous registry record. Therefore, you should only need to re-register when your credential data has changed.

Optional: Create a matcher

Credential Manager is protocol agonistic; it treats the metadata registry as an opaque blob and doesn't verify or check its contents. Therefore, the wallet has to provide a matcher, a runnable binary that can process the wallet's own data and generate the display metadata based on an incoming request. Credential Manager will run the matcher in a sandbox environment without network or disk access, so that nothing leaks to a wallet before the UI is rendered to the user.

The Credential Manager API will provide matchers for popular protocols, today OpenID4VP. It is not officially released yet, so for now use our sample matcher for the OpenID4VP v24 protocol.

Handle a selected credential

Next, the wallet needs to handle when a credential is selected by the user. You can define an Activity that listens to the androidx.credentials.registry.provider.action.GET_CREDENTIAL intent filter. Our sample wallet demonstrates this procedure.

The intent that launches the activity will contain the Verifier request and calling origin, which can be extracted with the PendingIntentHandler.retrieveProviderGetCredentialRequest function. The API returns a ProviderGetCredentialRequest containing all the information associated with the given verifier request. There are three key components:

  • The app which made the request. You can retrieve this with getCallingAppInfo.
  • The selected credential. You can get information about which candidate the user has chosen through the selectedEntryId extension method; this will match the credential ID that you registered.
  • Any specific requests that the verifier has made. You can get this from the getCredentialOptions method. In this case, you should expect to find a GetDigitalCredentialOption in this list, containing the Digital Credentials request.

Most commonly, the verifier will be making a digital credential presentation request so you can process it with the following sample code:

request.credentialOptions.forEach { option ->
    if (option is GetDigitalCredentialOption) {
        Log.i(TAG, "Got DC request: ${option.requestJson}")
        processRequest(option.requestJson)
    }
}

You can see an example of this in our sample wallet.

Render the wallet UI

Once the credential is selected, the wallet is invoked and the user is taken through its UI. In the sample, this is a biometric prompt.

Return the credential response

Once the wallet is ready to send back the result, you can do so by finishing the activity with the credential response:

PendingIntentHandler.setGetCredentialResponse(
    resultData,
    GetCredentialResponse(DigitalCredential(response.responseJson))
)
setResult(RESULT_OK, resultData)
finish()

If there's an exception, you can similarly send the credential exception:

PendingIntentHandler.setGetCredentialException(
    resultData,
    GetCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()

Refer to the sample app for an example of how to return the credential response in context.