Giter VIP home page Giter VIP logo

digital-credentials's Introduction

Digital Credentials

📄 Digital credentials explainer and draft spec.

This incubation is attempting to specify an API for user agents that would mediate access to, and representation of, verifiably-issued digital credentials.

These identities can range from government-issued documents, such as driver's licenses and passports, to start with, to other credential types, potentially in the future.

Digital Credentials builds upon Credential Management to enable the secure and private exchange of digital identity information. It facilitates authenticated interactions by representing digital credentials through the DigitalIdentity interface, which embodies verifiable claims about an individual's identity.

Scope

This project covers the requesting mechanisms for digital credentials, including secure presentation aspects. It does not yet encompass the issuance process for establishing a digital identity nor UI/UX considerations beyond privacy aspects related to data protection during the request process.

Trying out the API

🚧 Note: The API is still extremely unstable and undergoing a lot of changes (almost daily!). 🚧

However, if you want to try it out:

Contributing

This is an unofficial proposal under development. Contributions, feedback, and discussions are highly encouraged to refine and enhance the API specification. Join the WICG to help us in shape the future of digital identity management on the web.

Weekly Meetings

Initial proposals

The initial proposals have been moved to the proposals folder. They are still available as historical references.

digital-credentials's People

Contributors

agl avatar cwilso avatar dontcallmedom avatar github-actions[bot] avatar hober avatar marcoscaceres avatar msporny avatar or13 avatar rbyers avatar samuelgoto avatar timcappalli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

digital-credentials's Issues

Support for web-based wallets

One common use case that we've supported in the Credentials CG work, and CHAPI (Credential Handler API), for a while now is the ability to invoke web-based wallets to respond to a request. There is a lot of focus on high-assurance use cases these days (government-issued digital identity tied to hardware security keys on mobile phones and app attestations). This raises the bar for what a "digital wallet" is to a degree that is much higher than a number of other use cases in the VC ecosystem (education VCs, pseudonymous age-over assertions, pseudonymous digital coupons, etc.). It is also possible for a web-based wallet to deliver VCs that are signed by HSM-based keys. For these reasons, CHAPI supports the invocation of both web-based digital wallets and native digital wallets (as evidenced by multiple implementations in the latest JFF Plugfest 3).

Whatever this work ends up becoming, there needs to be a consideration for both web-based wallets and native wallets through the same interface.

Add CODEOWNERS file

It would be great to add an CODEOWNERS file that would automatically assign various folks for review. This doesn't not preclude anyone in the community from doing a review (highly encouraged!) but it does mean that at least a few CODEOWNERS must give a ✅ before a pull request is merged.

For CODEOWNERS, we should have small range of experts (too many cooks can spoil the broth).

Inclusions in CODEOWNERS is on a volunteer basis, but requires commitment/responsibility from those folks to do the review (i.e., no good deed goes unpunished, you need to allocate time to do the reviews and those need to be done in a timely manner).

API design should emphasize that sites should request minimal properties, not full identity documents

It might sound a little like bike-shedding, but I am concerned in seeing API methods called requestIdentity, as it seems to suggest that what you will get back is the user's complete identity.

If successfully, responsibly deployed, the vast majority of uses of this API should return responses with particular properties or claims or proofs from a credential, but not what the developer might think of as the user's identity.

How can we design an API that makes it clear that sites should ask for only what they need, and not over-ask?

(this is for dc2-proposal but I don't have label permission)

[Discuss] Requests for multiple credentials

There are use cases that we have in the W3C Verifiable Credentials Working Group that consist of presenting multiple Verifiable Credentials in a single Verifiable Presentation:

https://www.w3.org/TR/vc-use-cases/#citizenship-by-parentage

Other examples of this pattern include:

  • Submitting a digital driver's license and a liveness credential (the person that is interacting is the person that is on the card).
  • Submitting a passport and an assertion that the signing key for the presentation is protected by a Hardware Security Module (HSM)
  • Submitting an employment authorization document and an I-9 (Employment Eligibility Verification) form.
  • Provide a set of all course completion and continuing education credits for a particular calendar year.

In each of these cases, you want to bind these VCs together in the same presentation and doing multiple exchanges creates usability issues.

The current design of the Identity Credentials API is focused on requesting and presenting a single credential, which leads to usability and security concerns when an exchange requires multiple credentials. The group should consider if it is possible to support exchanging multiple credentials in a single exchange as that is what other systems (like CHAPI) are able to do today.

[DISCUSS] Do any wallets need TLS context from the browser (or app platform)?

This isn't really in scope for the web platform API itself, it is more for the OS platform plumbing, but wanted to have the discussion.

Will (some) identity wallets need context from the TLS session in the browser (or even the app platform in the case of a native app verifier), such as certificate attributes or awareness that a verifier (or issuer) presented with a Qualified Website Authentication Certification (QWAC)?

[Discuss] This API should address the Jevons Paradox around increased consumption of verifiable credentials and the rise of their abuses

Jevons Paradox is an economic principle which introduces the concept that availability and efficiency of providing a resource (in this case data from a driver's license) can often times lead to increased consumption of the resource. This spec should be addressing whether this additional consumption provides an overall net positive gain for the web platform or if this will cause further harm to marginalized communities of people.

While many people may consider this a given of any web api, in the specific case of a driver's license we're increasing access to sensitive PII in a verified way about a user. This raises ethical questions which may be in violation of the ethical web principles and privacy principles defined by TAG. Therefore it begs the question to what degree should the web platform be contributing to this phenomena and should this API be standardized in the first place?

More specifically, I think we need to specifically address what societal impact this additional API will bring to the further marginalization of vulnerable communities and whether the acceptance of this API into the web platform is worth the tradeoffs for those additional harms. By increasing access to sensitive, verified PII we're inadvertently also making it easier to justify the requirement of providing this data in order to access specific web services. While in some cases, many would consider this acceptable such as lawmakers in Louisiana[1] it will also introduce a slippery slope where many web services will request this data from a user in a way that stretches the boundary of "legitimate usage" of data. I'm sure we can all think of many more dystopic use cases that could be introduced because of the increased access to this data. For example, I'm sure there will be at least one government that contemplates requiring all users to provide this information to social networks so they can subpoena dissenting voices on social networks like Twitter and surveil or silence them because of this required deanonymization. Is that direction we're prepared to take the web in by introducing this API?

This was originally posted here: WICG/mobile-document-request-api#6

I don't want this to be lost, so am moving it over here.

After sitting on this idea a bit I think the direction we should look to technologically here is how we utilize intentional friction in order to reduce the likelihood of abuse. As an example, if we make it so easy to conduct a liveness test with this API then we'll also encourage liveness checks to be done at every authentication check. However, if it has a high level of friction to conduct a liveness check it may be only used for registration and important 2FA step ups.

Credential Management integration

The CM spec's Extensions points outlines the following things to do to integrate. Adding as a todo list:

This document provides a generic, high-level API that’s meant to be extended with specific types of credentials that serve specific authentication needs. Doing so is, hopefully, straightforward.

  • Define a new interface that inherits from Credential:

Define appropriate:

You might also find that new primitives are necessary. For instance, you might want to return many Credential objects rather than just one in some sort of complicated, multi-factor sign-in process. That might be accomplished in a generic fashion by adding a getAll() method to CredentialsContainer which returned a sequence<Credential>, and defining a reasonable mechanism for dealing with requesting credentials of distinct types.

For any such extension, we recommend getting in touch with [public-webappsec@](mailto:[email protected]) for consultation and review.

parameters not specific to the credential format

in the reconciliation example, nonce is duplicated in mdoc and federated, and readerPublicKey are included only in mdoc. since nonce and probably readerPublicKey should be present in vc too, those parameters should be treated as credential format specific.

So examples for MDocs and FedCM could look like below:

MDocs

// Gets a CBOR with specific fields out of mobile driver's license as an mdoc
const {response} = await navigator.credentials.get({
  identity: {
    providers: [{
      nonce: "gf69kepV+m5tGxUIsFtLi6pwg=",
      readerPublicKey: "ftl+VEHPB17r2 ... Nioc9QZ7X/6w...",
      mdoc: {
        retention: {
          days: 90,
        },
        documentType: "org.iso.18013.5.1.mDL",
        requestedElements: [
          { namespace: "org.iso.18013.5.1", name: "document_number" },
          { namespace: "org.iso.18013.5.1", name: "portrait" },
          { namespace: "org.iso.18013.5.1", name: "driving_privileges" },
          { namespace: "org.iso.18013.5.1.aamva", name: "organ_donor" },
        ],
      }
    }],
  }
});

FedCM

// Gets a JWT from a OIDC provider. 
const {response} = await navigator.credentials.get({
  identity: {
    providers: [{
      nonce: "m5tGxUIsFtLi6pwg",
      federated: {
        configURL: "https://university.edu/students",
        clientId: "123"
      }
    }]
  }
});

Expressing requested claims in the Verifiable Credentials example

for a verifiable credential example,if a credential format is specified (vc+sd-jwt in your example), there is no need to provide a JSON.Path to different potential variations of how a claim name can be expressed, because "the path" where to find a claim name will be determined by the credential format and credential type.

Could a structure like below be sufficient?

// Gets a SD-JWT from a VC holder.
const {response} = await navigator.credentials.get({
  identity: {
    providers: [{
      vc: {
        nonce: "m5tGxUIsFtLi6pwg",
        format: { 
            vc+sd-jwt: { 
                alg: ["EdDSA", "ES256"]
            }
         },
         type: "UniversityDegreeCredential",
         credentialSubject: {
             family_name: {
	         intent_to_retain: false
              },
             birth_date: {
		   mandatory: true,
             },
             driving_privileges: {
             } 
         }
      }
    }]
  }
});

Clearly separate presentation of issuer-signed Credentials from User Authentication Event

I do not think it is a good idea to use identity credentials for authentication. and I worry that allowing to combine federated and mdoc or vc in the same API like shown in the Reconciliation section fosters exactly that.

In Federation, it is the Issuer (IdP) who authenticates the user (proof of authentication is ID Token, SAML assertion, etc.). For example in the ID Token, iss and sub claims are mandatory and are used to express that iss authenticated the end-user identifier as sub. ID Token does have data about the end-user, but it is only meaningful because it is combined with an authentication proof: "Issuer authenticated the user and is providing some values relying party can use"

Identity Credentials (placeholder term for both mdocs and VCs) are different. There, user authentication is optional and if performed, it is the Wallet (not the credential issuer) that authenticates the user when presenting issuer-signed credentials. So a user identifier assigned by the issuer does not have any meaning for the verifier as it does not bound to authentication - the sub claim in the issuer-signed credential is optional (in fact mdocs do not have an equivalent to a sub claim in the ID Token; in W3C VCs it is used to discover the keys to validate the signature by the user's key). the value of the identity credential is orthogonal to user authentication, "Wallet is proving that a certain issuer-signed credential has not been tampered with and is being presented by a legitimate user". with identity credential presentation, there is a need for a separate proof of authentication - can be Passkey, Self-Issued ID Token, etc.

maybe it is a good idea to have a same API for federation and mdoc/vc, but allowing to combine federation and mdoc/vc in one API call is concerning.

Hope this makes some sense..

Consider Verifiable Presentation Request design patterns

Based on commentary in this issue about the complexity in PeX and it being viewed as too complicated for a presentation request language (I agree):

https://bitbucket.org/openid/connect/issues/1917/moving-to-a-credential-format-specific

The charter should consider the design approach taken in the Credential Handler API (CHAPI) and the Verifiable Presentation Request (VPR) work. Namely, that the design is meant to be protocol and query language agnostic. That is, it is designed to support mdoc query languages, VC query languages, and different protocols for mdoc, VCs, and other market vertical formats:

Demonstration of being query language agnostic:
https://w3c-ccg.github.io/vp-request-spec/#query-and-response-types

Demonstration of being protocol agnostic:
https://w3c-ccg.github.io/vp-request-spec/#interaction-types

While the examples are out of date, the design pattern still holds (and it looks like the discussion in the OpenID community is converging on the same design pattern that was established by VPR many years ago).

Fundamentally, the query languages and protocols for moving the newest types of digital credentials over the Web, NFC, and QR Codes are very new and unsettled. Trying to lock one in at this moment in time, or in a WG over the next 1-2 years is premature. Thus, the safest design approach would be to allow for agility at both the query language layer and the protocol layer.

[Discuss] Solution scope

Surfaced as a core discussion topic on the first call (2023-10-04).

  • Bigger picture of the API: presentation, issuance, web wallet interactions, etc
  • help from client for wallet selection, role of UA and platforms, cross-device

Do we really need `publicKey` to be outside of the `request` property?

In this, publicKey is part of the top-level parameter.

dictionary IdentityRequestProvider {
 required DOMString protocol; // See "Protocol Registry" below
 required DOMString request;
 required DOMString publicKey;
}

Should publicKey be (opaquely, optionally and per protocol) part of request instead of IdentityRequestProvider?

No IdentityCredential sub-types may be [[Store]]d or [[Collect]]ed

Adding

IdentityCredential includes CredentialUserData;

would make it so Identity Credentials may be put into the Credential Store, so they can be stored client side and presented in a "credential chooser" as shown here. Some types may want this, while others may not, so it is worth considering what combinations to permit. Currently this permits none.

[Discussion] Integrate with web wallets?

CHAPI went through great effort to integrate with both native and web wallets, as do other similar APIs like PaymentRequest. At the moment we've focused here mostly on native wallet integration.

At a minimum I think we need to convince ourselves that a V1 API could be compatibly extended to support web-based wallets.

nonce missing in the Verifiable Credentials example

nonce should be mandatory to be included in the returned Verifiable Presentation and binds it to a transaction. (nonce might not be explicitly mentioned in the W3C vc-data-model, but it is because how to transport VCs is out of scope of that document).
(I included nonce in the example in the Issue #5)

Requirements and Objectives

Hi all,

I have been told a couple of times the fundamental issue this group wants to solve is to find an alternative to custom schemes for invoking wallets. I agree with that objective as custom schemes are less secure than app/universal links and really brittle.

To understand what is needed one needs to take a look on what custom schemes are used for today in this context. In OpenID 4 VC we use custom schemes on the interfaces between verifiers & wallets and issuers & wallets to discover & invoke a wallet in cases where there could be multiple wallets serving the same purpose, typically in a certain ecosystem.

One example will be the EU's eIDAS wallet ecosystem. All the EUDI wallets will provide the same feature set through the same interfaces with the same formats as defined in the regulation and further detailed in ARF and implementing acts. As a verifier, I would like to talk to them without the need to write specific code for every of those wallets. I also need a mechanism to invoke one of the EUDI Wallets installed on the user's device. Custom schemes are today the only way to do that.

So in my opinion, if we want to replace custom schemes, we at least need to provide a mechanism resolving an alias representing a coherent set of wallets into one or more wallets for a certain user and device.

However, all the proposals submitted in this group go much further as they invent new protocols/APIs for requesting and presenting credentials. Why is that? There are protocol for that in the market already, e.g. OpenID 4 VC, RestAPI, DIDComm, CHAPI, ...

I think the first increment (one could call it MVP) should be an API resolving a symbolic name (e.g. "EUDIW") to URLs (or other types of addresses as used by the respective protocols). The benefit for the ecosystem is obvious, existing implementations of the before mentioned protocols could be improved very quickly. I would love if the user had the choice what wallet to use in case multiple wallets are installed on the device, it would be great if the user could install a wallet on demand instead of sending the flow to dev nil if no matching app is installed, user could open wallets with much more confidence as there would be some mechanism (like for app/universal links) to make sure only legit apps could claim a certain alias. Awesome!

A second step could be to define a browser APIs for credentials. However, to come up with a compelling solution, such an API (in my opinion) must cover the following features:

  • credential format agnostic: it must support use of any credential format as there a lot of credential formats in the market and they should all be supported.
  • presentation & issuance: issuers must find and invoke a wallet in the same way as a verifier. A comprehensive solution therefore must support both sides of the three party model and cover presentation in the same way as issuance. I'm being frequently told issuance cannot be standardized. Based on our experience w/ OpenID 4 Verifiable Credential Issuance I would say: it's hard but it is possible. And it is needed to give users the choice, foster adoption of the model and prevent lock in.
  • cross device: the before mentioned points are all already covered by OpenID 4 VC, so a browser API not providing more would not be compelling to implementers. That's why I believe such an API would need to cover cross device scenarios as we know we can cover those much more securely with browser/platform support.

Please be aware the second step might introduce a lot of challenges regarding scalability of the system, security, privacy, and regulation.

  • scalability of the system: whatever the feature set of the API is, it won't be sufficient and will need to be extended as the three party model is still evolving very quickly. Are the browser venders willed to keep up with that?
  • security & privacy: a lot of data will be flowing through the browser that are security relevant (such as nonces) and PII (in credentials). I already hear it "we will encrypt everything". Well, that will make the developers live harder.
  • regulation: Also please be aware that the more functions are put into browser and platform the more likely those components will be subject to regulation, i.e. they need to be certified, the provider perhaps even becomes part of the auditing/reporting/incident notification chain of the respective wallet provider. That's no fun.

The alias approach does not pose any of those problems.

best regards,
Torsten.

Is only MDocs response expected to be encrypted?

FedCM and VC examples do not contain readerPublicKey. Does that mean those responses are not expected to be encrypted? or in the case of FedCM, IdP is supposed to use publicKey of the RP it has obtained during pre-registration..?

API requests should provide the site with what they need to explain why and how requested credential information will be used

Opaque, protocol-specific request strings don't allow site authors to indicate why and how each field in the request will be used, or to provide the context for a user to make a reasonable decision.

We could also open similar issues on the other specifications (although I'm not sure those organizations do work in public or would be interested in accepting feedback at this stage). But since the request is coming from the web site and in the context of a rich HTML page, this API is exactly the place to enforce that requests are legitimate and explained to the user.

(for dc2-proposal)

Is "requestIdentity()" the best method name and do we need it?

As part of PR 57, @samuelgoto wrote:

We don't have to do this all at once, but I'm wondering if something like a requestDigitalCredential may be a better (more specific ) method name in comparison to requestidentity ... again, because this is going to collide with Chrome's implementation of the IdentityCredential which FedCM uses.

We should consider some alternatives or decide if we are ok with requestIdentity().

Is there a case where requestIdentity() resolves with null?

To me, it seems like throwing an exception if the user did not choose to share their mdoc / does not have one on their device is an awkward pattern (especially in Javascript with no exception types). Preferably, a call to credentials.get() should return an empty response if a user chose not to share an mdoc instead

Psuedocode:

try {
  const credential = await credentials.get(...);

  if (credential.hasResponse()) {
     // handle credential response
  }

  // do nothing
} catch (e) {
  // handle truly unexpected errors
}

[PROCESS] "pending close" should only be used after result of discussion is documented

There are a few issues that have been marked "pending close" without it being clear why they're being marked as such:

#32
#39
#43

This comes across as arbitrary closing of issues instead of what's probably happening, which is that the issue was discussed on a call and that resulted in some rough consensus on a conclusion like: "Rough consensus is to do X."

Please document why the issue is being closed with a simple conclusion before closing issues. A sentence or two will do in most cases.

How much is really in common between different `IdentityCredential` types?

One piece of feedback we've heard is that it seems premature to unify different credential types into IdentityCredential if all they're really sharing is a nonce and response and if the IdentityCredentialRequestOptions is simply a list of unrelated queries.

On the one hand, the main reason we want to unify is so that we can enable credential-picker UIs which list different types of identity credentials all together. This doesn't actually require any unification beyond a common API call (or some other way to group multiple calls into a single UI transaction).

On the other hand, there are actually things we expect to be in common, so perhaps it's worth trying to sketch that out in more detail. In particular, is it useful to think of different layers in the identity-verifying application stack and ask if abstraction can help simplify the design of some components (including the browser itself). Eg. if we add abstraction across selective disclosure, filtering and/or UI presentment of disparate credentials, does that provide sufficient concrete benefit to justify the abstraction?

[Discuss] Limit access to the API based on known allow listed origins

In order to reduce harmful over-requesting of 3P attested information it would be useful to have a registry of origins allowed to request credentials. If the origin is not listed then the site would not be able to prompt the user for permission of the credential.

The default lists will need to be maintained. Two proposals for this registry would be W3C or country specific privacy commissioners who publish them in a way that the browser services can load and store them.

Should we also allow users to be able to override them and if so what is the proper UX for this? If so would it make sense to do this as a part of the permissions UX currently implemented or as a UX with more friction?

Using CryptoKey for public keys - what are the restrictions?

Right now, we had proposed passing around DOM strings for public keys... However, CryptoKey serves as a nice primitive we already have in the platform from Web Crypto.

I think we can reuse the crypto.subtle.subtle.importKey() method to get the CryptoKey, which we can then pass into requestIdentity() as part of the IdentityRequestOptions.

Registry inclusion criteria

We need to come up with a registry governance and inclusion criteria.

For inclusion, at a minimum, there should be implementation support, and we talked about having some privacy checks too.

Separating identity and authentication in the API shape

Probably the most straightforward way would be to split something identity-specific off of the existing navigator.credentials.get(), which would then be used for non-identity stuff. navigator.credentials.getIdentity() maybe?

[HOWTO] Try the Prototype API in Chrome/Android

Identity Credentials Quick Start Guide

Sept 2023

This HOWTO will guide you through to with with the prototype of the API in Chrome and Android. It is a bit cumbersome at the moment because it is in its early stage of incubation (e.g. protected by flags). If you run into problems, feel free to ping @leecam or @samuelgoto on slack.

Test device setup

  1. Enable the Identity Credential API on Android
    1. Enroll your Android device in the Google Play Services Beta program as per instructions here:
      https://developers.google.com/android/guides/beta-program
    2. Once Google Play Services has updated, ensure the version is greater or equal to 23.40.xx. This can be found by going to do Settings->All apps->Google Play Services
  2. Enable the Identity Credential API in Chrome
    1. Install the chrome canary build
      https://play.google.com/store/apps/details?id=com.chrome.canary&hl=en_US&gl=US
    2. Open chrome and go to chrome://flags, search for digital credentials and enable that flag

Testing the setup

You should now be able to test the Identity Credential with our sample apps to verify your setup:

  1. Install the sample wallet app here. It will appear in the launcher as IC Purse
adb install -t <path-to-apk>
  1. Install the sample reader app here. It will appear in the launcher as App Verifier
adb install -t <path-to-apk>
  1. Launch the App Holder app and provision a new mDL
    1. Tap the menu button and select Add Self Signed Document
    2. This document will now be available for presentment to native apps and websites
  2. Launch the App Verifier app and tap Request via Credential Manager. This should invoke the Credential Selector UX showing the available documents that match the request. At this point you see the mDL you provisioned above.
  3. Select the mDL. The Verifier app will now show the information it received.
  4. You can also test via the web.
    1. Navigate Chrome Canary to www.identitycredential.dev and ensure you also request the mDL successfully.

You can use this website and reader app to test and verify your wallet application. You should see your credentials alongside credentials from our sample wallet.

If you got this far, you should have something that looks more or less like the following:

https://www.youtube.com/watch?v=mZeSVNK0jlw

Verifier API

You can build a website that uses the JS API to request documents on the web.

// Gets a CBOR with specific fields out of mobile driver's license as an mdoc
const {response} = await navigator.credentials.get({
  identity: {
    providers: [{
      holder: {
        selector: {
          format: ["mdoc"],
          retention: {days: 90},
          doctype: "org.iso.18013.5.1.mDL",
          fields: [
            "org.iso.18013.5.1.document_number",
            "org.iso.18013.5.1.portrait",
            "org.iso.18013.5.1.driving_privileges",
            "org.iso.18013.5.1.aamva.organ_donor",
          ],
        },
        params: {
          nonce: "gf69kepV+m5tGxUIsFtLi6pwg=",
          readerPublicKey: "ftl+VEHPB17r2 ... Nioc9QZ7X/6w...",
        }
      }
    }],
  }
});

You can also build a native app verifier by calling the following API:

TODO(@leecam): write the instructions on how to use the CredMan API for requesting digital credentials

Holder API

Building the sample wallet app

You can build our samples as a starting point and have a play.

  1. Setup a local maven repo. Download the local maven repo from here
# cd ~/.m2/repository
# unzip idsdk.zip
  1. Check out the sample code
    The code for the sample apps is here https://github.com/google/identity-credential/tree/android-credential-manager
    Make sure you use the android-credential-manager branch
  2. Load the project in Android Studio
  3. You can build the App Holder app and install it on your device

You should now be able to use the use the demo apps as before

Setting up the SDK in your app

Note: Remember to only use the two app package names you shared with us. We allow-listed them to use this API while the API is still under development so that we can control backwards incompatible breaking changes.

  1. You need to add the local maven repo to your settings.gradle file.
  2. You can do this by adding mavenLocal() to the repositories section.
  3. Next add the SDK dependency to your build.gradle.
 implementation 'com.google.android.gms:play-services-identity-credentials:0.0.1-eap01'

e.g https://github.com/google/identity-credential/blob/android-credential-manager/appholder/build.gradle#L80

Where to look in the sample wallet

The credential registration happens here:
https://github.com/google/identity-credential/blob/android-credential-manager/appholder/src/main/java/com/android/mdl/app/document/DocumentManager.kt#L88

The Provider API

Note: This API will be provided as part of the Credential Manager Jetpack Library. Unfortunately we can’t share this with you directly quite yet. Instead you’ll use some slightly lower-level APIs. Jetpack just provides more developer friendly wrappers over the API you’ll be using today. It's still fairly straightforward but note that when this API is released the public API will be exposed via Cred Man.

The incoming request parameters are provided to your wallet app as a JSON string. This JSON string is provided by the calling RP application. The specification of this JSON is currently being defined by the W3C, but this API doesn’t concern itself with its contents. It is the responsibility of your wallet app to parse this request and form the response.

Chrome and our test apps provide the JSON in the following form. This is just a simple request format to demonstrate the API, this will likely evolve in the W3C working group. This is the RedBox in David’s ISO presentation.

{
  "providers": [
    {
      "responseFormat": "mdoc",
      "selector": {
        "fields": [
          {
            "name": "doctype",
            "equal": "org.iso.18013.5.1.mDL"
          },
          {
            "name": "org.iso.18013.5.1.portrait"
          },
          {
            "name": "org.iso.18013.5.1.family_name"
          },
          {
            "name": "org.iso.18013.5.1.given_name"
          },
          {
            "name": "org.iso.18013.5.1.document_number"
          },
          {
            "name": "org.iso.18013.5.1.expiry_date"
          },
          {
            "name": "org.iso.18013.5.1.issue_date"
          },
          {
            "name": "org.iso.18013.5.1.age_over_18"
          },
          {
            "name": "org.iso.18013.5.1.aamva.DHS_compliance"
          },
          {
            "name": "org.iso.18013.5.1.aamva.EDL_credential"
          }
        ]
      },
      "params": {
        "nonce": "ZWuRXfcV7-iRkZH4puWnRA==",
        "requesterIdentity": "BOHjVu78FDoBZdxmSn6EOfcC1Eam8c9XCKjblABWpt4="
      }
    }
  ]
}

The provider API allows you to define the matching logic used by your wallet to decide which documents/credentials to show in Credential Selection UI for a given json request.

This matcher logic is defined as a wasm module that you register with the system as follows

val registrationRequest = RegistrationRequest(
      credentials = yourMetaData,  // A binary blob that we pass to your matcher
      matcher = yourMatcherBinary, // The wasm module 
      type = "com.credman.IdentityCredential" // has to set to this
    )

val client = IdentityCredentialManager.Companion.getClient(context)
client.registerCredentials(registrationRequest)

Android will execute your wasm matcher in a sandbox upon receiving a request from an RP application or website. The matcher binary will be provided with the credential data blob you provide as part of registration, the incoming request json from the calling RP and the calling app information (calling packagename or origin). The matcher's job is to parse the incoming request and to populate the entries in the selector UX.

As per above, we will provide more developer friendly APIs in jetpack towards the end of the year. This includes default matchers and helper classes. So most wallets won’t need to deal with writing their own matcher unless they have some complex matching logic or want to support a new credential type.

For this proof of concept you can use the matcher from our demo app. You can place it in your assets folder in your app. You can find it here:
https://github.com/google/identity-credential/tree/android-credential-manager/appholder/src/main/assets

There are 3 helper classes that you can copy and paste into your wallet app, they can be found here:
https://github.com/google/identity-credential/tree/android-credential-manager/appholder/src/main/java/com/android/mdl/app/credman

These helpers use the provided matcher and build up the credential data in a structure the matcher understands.

You can use these helpers to register a simple credential as follows:

val fields = mutableListOf<IdentityCredentialField>()
// Add the doc type field
fields.add(IdentityCredentialField(
name = "doctype",
       value = "fakedoc",
       displayName = "Document Type",
       displayValue = "Fake doc type"
))

// Add a name field
fields.add(IdentityCredentialField(
name = "firstname",  // field name is required for matching the fields in the json
       value = "Erika",  // the vaule is optional.
       displayName = "First Name", // required to show the matched fields in the selector
       displayValue = "Erika"  // the vaule is optional.
))

// Create the entry
val entry = listOf(IdentityCredentialEntry(
id = 1, // will be passed to your app if the credential is picked by the user
       format = "mdoc",
                title = "Erika's's Driving License",
                subtitle = "California DMV",
                icon = BitmapFactory.decodeResource(context.resources, R.mylogo),
                fields = fields.toList(),
                disclaimer = null,
                warning = null,
 ))

// Create the registry with the list of entries
val registry = IdentityCredentialRegistry(listOf(entry))
// Register using the stock matcher 
val client = IdentityCredentialManager.Companion.getClient(context)
client.registerCredentials(registry.toRegistrationRequest(context))

Once you implement the above registration flow, you can test the web app, your credentials should appear in the selector (assuming they have the required fields to be considered a match).

Invocation

This API attempts to provide a huge amount of flexibility for the wallet application. The goal is to just handle credential selection and wallet invocation. All Android requires is that the wallet (via the matcher) provides enough information about the credential and the requested attributes that we can render a selector. This information allows the user to make an informed choice about which document to proceed with.

Once a credential is selected by the user Android will intent into the wallet app, where it can show its own UI to gather consent from the user, e.g by showing a biometric prompt. Our sample app doesn’t show any UI, but we suggest your app shows at least a biometric prompt.

You need to add a new Activity to your app with the following intent handler in the manifest
com.google.android.gms.identitycredentials.action.GET_CREDENTIALS

Here is an example:

<activity
            android:label="@string/app_name"
            android:name=".GetCredentialActivity"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="androidx.identitycredentials.action.GET_CREDENTIALS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

Android will invoke this Activity if your credential is selected by the user. You should use it to obtain user consent and form the response.

Again helper libs will do most of this heavy lifting in the future but for now you’ll be exposed to a bit of the plumbing.

Our sample Activity is here: https://github.com/google/identity-credential/blob/android-credential-manager/appholder/src/main/java/com/android/mdl/app/GetCredentialActivity.kt

In your onCreate method you should obtain the request:

// The JSON from the calling app
val request = extractGetCredentialRequest(intent)

// the credential ID of the selected credential (registered above)
val credentialId = intent.getLongExtra(EXTRA_CREDENTIAL_ID, -1)

// The calling app info
val callingAppInfo = extractCallingAppInfo(intent)

You should parse the request and generate the response for the selected credential.

The response is provided as a ByteArray. Our demo apps place a base64 encoded string of encrypted response in this byte array. (at some point we’ll change this to a string)

This string is passed directly back to the calling app. Again Android does not concern itself with the format of the request or the response. We leave it to the wallet to understand the format of the request and generate the response.

The response is provided as follows (again helpers in the future will hide some of these gory details):

val bundle = Bundle()
// you need to generate the encodedCredentialDocument
bundle.putByteArray("identityToken", Base64.encodeToString(encodedCredentialDocument, Base64.NO_WRAP or Base64.URL_SAFE).toByteArray())
val credentialResponse = com.google.android.gms.identitycredentials.Credential("type", bundle)
val response = GetCredentialResponse(credentialResponse)
val resultData = Intent()
setGetCredentialResponse(resultData, response)
setResult(RESULT_OK, resultData)
finish()

How to generate the response

The best way is probably to look at the sample code :)

The logic starts here: https://github.com/google/identity-credential/blob/android-credential-manager/appholder/src/main/java/com/android/mdl/app/GetCredentialActivity.kt#L151

Much of the heavy lifting is performed in this class:
https://github.com/google/identity-credential/blob/android-credential-manager/identity-android/src/main/java/com/android/identity/android/mdoc/util/CredmanUtil.kt

Its a standard mdoc device response CBOR, encrypted with HPKE. The main change is the session transcript, which is generated here:
https://github.com/google/identity-credential/blob/android-credential-manager/appholder/src/main/java/com/android/mdl/app/GetCredentialActivity.kt#L158

Note: We always set the calling package name to "com.android.mdl.appreader" in our sample apps, so you’ll need to do this too until we fix this hack.

Integrate with FedCM?

How can we best support a single UI for selecting from either wallet or federated credentials? Eg. for proving age or organization affiliation.

Split off from #10, no longer a v1-blocking concern for Chrome.

User story driven API design

During the discussions regarding the establishment of a W3C working group, several questions have emerged about integrating verifiable credentials, mdocs, and federated assertions into a unified interface and API surface. To better understand how users are likely to engage with these credentials, it may be useful to frame the discussion in terms of a user story or journey. Doing so could help us achieve greater alignment on this approach.

A mobile driver's license is a clear example of an identity credential that can serve as proof of age. However, there are also situations where a federated identity provider could offer verified age information through an OIDC ID token. Likewise, a request for proof of employment could be fulfilled by either a verifiable credential from a wallet or an assertion from LinkedIn via OIDC.

Developers typically rely on OIDC ID tokens as a familiar assertion format that enjoys broad industry support. In some cases, the trust established with the identity provider may be sufficient to satisfy verifiers. Additionally, the end user may already have a session established with the IdP and prefer not to retrieve a wallet-based credential from their phone. Alternatively, the user may be hesitant to directly share information from their driver's license with a verifier.

For this example, we can imagine a credential picker-style experience that assists the user in presenting the appropriate age or employment proof to the verifier, based on the user's level of comfort and the verifier's requirements.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.