Credential Handler API polyfill





GitHub Stars



Last Commit

3mos ago






Size (min+gzip)




Type Definitions





Credential Handler API polyfill (credential-handler-polyfill)

Credential Handler API (CHAPI) polyfill for browsers

The CHAPI polyfill provides a number of features that enable the issuance, holding, presentation, and general management of Verifiable Credentials, Authorization Capabilities, and a variety of other cross-origin credentials.

Animation showing selection of Credential Handler

See the feature videos for more animations of CHAPI in action.

Table of Contents


Credential Handler API (CHAPI) is:

  • a browser API
  • lets web apps securely get() and store() credentials, without having to roll their own wallet infrastructure
  • provides a secure trusted UI for users to manage those credentials
  • gives users ability to choose service providers for wallets

Read more: CHAPI Motivation and Background.


Take a look at the following websites to try out a minimal CHAPI implementation:



Loading the Polyfill

Before you can get and store credentials, you need to load the polyfill library.

If you're loading the polyfill from a <script> tag, you will have access to the navigator.credentials and credentialHandlerPolyfill globals.

const polyfill = window.credentialHandlerPolyfill;

Otherwise (if you're developing on Node.js and using Webpack, for example), import it in the usual manner:

import * as polyfill from 'credential-handler-polyfill';

Load (async):

await polyfill.loadOnce();
console.log('Ready to work with credentials!');

Requesting and Storing Credentials

A web application can get() and store() credentials without knowing anything about the user's wallet. This is intentional; for privacy reasons, the client app must not be able to query any information (without user consent) about which wallets or credential handlers a user may have installed (otherwise, fingerprinting and other attacks would be possible).


A web app (a Relying Party or verifier) can request a credential using credentials.get() during a user gesture event, for example when the user pushes a button on a page that requires identity attributes or authentication.

const credentialQuery = {web: {}}; // TODO: Update to something more useful
const webCredential = await navigator.credentials.get(credentialQuery);

if(!webCredential) {
  console.log('no credentials received');


A web app (for example, a credential issuer such as a university or institution) can ask to store a credential during a user gesture event, for example when the user pushes a button to receive a credential.

TODO: Expand on WebCredential object

const result = await;
if(!result) {
  console.log('store credential operation did not succeed');


TODO: Discuss creating and receiving WebCredential instances

When working with VerifiableCredentials (just one type of credential supported by CHAPI), a VerifiablePresentation is used to both store or present VerifiableCredentials. When storing a VerifiableCredential, the VerifiablePresentation does not need to be signed.

const presentation = {
  "@context": [
  "type": "VerifiablePresentation",
  "verifiableCredential": [{
    "@context": [
    "id": "",
    "type": ["VerifiableCredential", "AlumniCredential"],
    "issuer": "",
    "issuanceDate": "2010-01-01T19:73:24Z",
    "credentialSubject": {
      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
      "alumniOf": {
        "id": "did:example:c276e12ec21ebfeb1f712ebc6f1",
        "name": {
          "value": "Example University",
          "lang": "en"
    "proof": {
      "type": "RsaSignature2018",
      "created": "2017-06-18T21:19:10Z",
      "proofPurpose": "assertionMethod",
      "verificationMethod": "",
      "jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM"

const webCredential = new WebCredential('VerifiablePresentation', presentation);

Handling Empty Results

If the get() or store() operation resolves to a null value, this means one of two things:

  1. The user has denied or canceled the request
  2. The user does not have a wallet (credential handler service) installed

As mentioned previously, there is (intentionally) no way for the client to know which of these is the case.

As an app developer, the recommended way to handle this situation depends on your specific use case. This dilemma is familiar to mobile app developers asking for specific phone permissions (to access the camera or location, for example).
It is up to you to decide whether your app has fallback mechanisms, or whether the operation is required and things come to a halt without it.

Typical ways of handling empty results may include:

  • Invite the user to install a wallet if they haven't already (and provide a link/recommendation)
  • (In case the user denied the request) Invite the user to retry the operation, after explaining why you're asking to get or store the credential
  • (If possible/applicable) Provide an alternate path to the user (the conceptual equivalent of allowing "Guest Checkout" if the user has refused to register for an ecommerce account).

Advanced Operations for Wallet Providers

For most web app developers, your only interaction with the Credential Handler API will be through the get and store operations.

However, if you're a service provider aiming to offer users a credential management service or a wallet, you will need the advanced API to prompt the user for permission to install, to activate the handler, and so on.

Requesting Permission and Registering the Handler

const {CredentialManager, CredentialHandlers} = polyfill;

const result = await CredentialManager.requestPermission();
if(result !== 'granted') {
  throw new Error('Permission denied.');

// get credential handler registration
const registration = await CredentialHandlers.register('/credential-handler');


Including Credential Handler API in browser scripts

Adding the following <script> makes the navigator.credentials and credentialHandlerPolyfill globals available to your code.

<script src=""></script>

Installing using Node.js (for development)

To install as a dependency of another project, add this to your package.json:

"credential-handler-polyfill": "^2.1.0"

If you plan to develop or modify this polyfill, install it from Github:

git clone
cd credential-handler-polyfill
npm install


The CHAPI polyfill provides a number of features that enable the issuance, holding, presentation, and general management of Verifiable Credentials, Authorization Capabilities, and a variety of other cross-origin credentials.

Add Credential Handler

You can add a Credential Handler by calling the CredentialHandlers.register() API. This call will ensure that the individual using the browser explicitly confirms that they want to use the website as a credential handler.

Animation showing addition of a Credential Handler

Store Credentials

CHAPI supports storing credentials via the API. Storage of credentials prompts the individual using the browser to confirm that they want to store the credential in their digital wallet.

Animation showing storage of Credentials

Present Credentials

CHAPI supports the presentation of credentials via the navigator.credentials.get() API. CHAPI is agnostic to the presentation request query language and passes the query directly through to the credential handler. When presenting credentials, the individual is shown what they will be sharing and must provide explicit consent before the credentials are shared with the requesting party.

Animation showing request for a Credential

Select Credential Handler

Multiple credential handlers may be registered. If an individual has multiple credential handlers registered, they are given the option of selecting between the handlers or setting one as the default on a per-website basis.

Animation showing selection of Credential Handler

Hide Credential Handler

When an individual desires to not use a credential handler anymore, they can hide that credential handler via the interface. If they accidentally click the hide button, they have several seconds to undo the action. Credential Handlers that are hidden can be added again by going to the registration website.

Animation showing hiding of Credential Handler

Just-In-Time Install of Credential Handler

If an individual has no credential handlers registered, the website that uses CHAPI can suggest up to three credential handlers that can be "just in time" installed so that the original storage operation can complete.

Animation showing Just-In-Time Addition of Credential Handler

Works on Mobile

CHAPI is designed to run on desktop, tablet, and mobile form factors. The interface is responsive to provide the best experience for each form factor.

Animation showing Credential Handler working on Mobile


This polyfill makes use of a UI that emulates secure browser UI (also known as "browser chrome"). This polyfill UI is an emulation and IS NOT implemented by the browser. Support for the Credential Handler API could make this UI (or most likely a much better one!) a reality in browsers in the future.


See the contribute file!

PRs accepted.

Note: If editing the README, please conform to the standard-readme specification.

Commercial Support

Commercial support for this library is available upon request from Digital Bazaar:


New BSD License (3-clause) © Digital Bazaar

Rate & Review

Great Documentation0
Easy to Use0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Unwelcoming Community0
No reviews found
Be the first to rate


No alternatives found


No tutorials found
Add a tutorial