A common protocol for decentralized entities to exchange Verifiable Credentials across various communication channels.
Comments regarding this document are welcome. Please file issues directly on GitHub, or send them to public-credentials@w3.org (subscribe, archives).
Portions of the work on this specification have been funded by the United States Department of Homeland Security's Science and Technology Directorate under contracts DHS (OT) 70RSAT20T00000005. The content of this specification does not necessarily reflect the position or the policy of the U.S. Government and no official endorsement should be inferred.
Work on this specification has also been supported by the Department of Homeland Security SVIP program, the Decentralized Identity Foundation (hopefully) and the Hyperledger Aries community (blockcert?).
The objective of this specification is to define a common, minimalist message protocol for Issuers, Holders and Verifiers for the purpose of requesting and exchanging W3C Verifiable Credentials and Presentations across technology boundaries.
This protocol is meant to be transport agnostic; certainly it must operate in Web based scenarios, but it also must be compatible in offline (sometimes even connection-less) scenarios. Therefore this specification will first define the messages, and then later in the document various bindings will be defined.
There are currently multiple standard (and developing standard) protocols for facilitating the actual transfer of Verifiable Credential data, for example Aries DIDComm and the Credential Handler API (CHAPI), and more popular frameworks like OAuth and OpenID Connect may also be used. Most of these protocols provide a high degree of flexibility in their message structure, making them useful beyond Verifiable Credentials. This protocol will therefore treat these generic transfer technologies as Communication Channels - or 'pipes' for facilitating message transfer. This will allow developers to build Verifiable Credential based systems in a way that they are guaranteed some level of interoperability decoupled from more feature rich protocols and technology stacks.
The goal of this specification is to define a common message structure so that Issuers, Holders, and Verifiers can exchange Verifiable Credentials across these Comm Channels: entities using the same Comm Channel can operate over that channel, and entities integrated to different channels may rely on 'adapter' software to pass these messages across those channels; and still process the request/response to exchange credentials. Sessions may even initiate on one channel and transfer to another during the course of the communication.
This protocol takes into account and aims to be interoperable with the following:
Out of scope for this specification are the details of how various technologies make use of Encrypted Data Vaults, message routing or proxying, multi-party (3+) extensions, and Verifiable Presentation privacy considerations (unless they are part of the message structure).
Note it is also possible that during the course of this messaging entities may determine they cannot interoperate due to the nature of the schemas and formats of the Verifiable Credentials being exchanged; this is an unfortunate but acceptable outcome. For example, a Holder simply may not have the Credentials matching the requested Schema by the Verifier. The Issuer may not be able to support a particular signing algorithm required by the Holder. C'est la vie.
This protocol specification is meant to sit atop the Verifiable Credentials v1.0 data format, the various Communication technologies and the transport layers. The following diagram is a visual (but not exhaustive) representation of how the various components in a Decentralized Identity ecosystem fit. Your mileage may vary.
When the protocol can be used in conjunction with a particular message transport technology, this is referred to as a binding. Sample bindings are included in the Annex, and may be expressed as separate specifications.
The following diagram illustrates the message flow for request/issuance and request/presentation of Credentials. The flow is an extraction for the commonalities among the various considered Comm Channels.
Dotted lines represent optional steps. All messages are transport agnostic.
I am not sure this message belongs as part of this protocol - during the Response these custom details may simply be negotiated for a particular Comm Channel.
The following are use cases this Protocol looks to enable. It should be reiterated that although there are already Comm Channels which may enable some of these use cases, the goal of this Protocol is interoperability across Comm Channels.
Scenario 1: Web Browser only. In browser JavaScript/plugin enables Credential exchange.
Scenario 2: Cloud Holder. User has a web service as a Holder.
Scenario 3: OAuth Holder. A Website integrated with OAuth can obtain data from a Verifiable Credentials Holder acting as an Authorization Server and Resource Server.
Scenario 4: Mobile Holder A user with a Mobile App Holder can share credentials with a cloud service.
Scenario 5: Peer to Peer. Two individuals with different Mobile Apps can exchange credentials, even when they have no Internet connectivity. One of the Apps may be an automated Kiosk.
Scenario 6: Physical Presentation. A user can scan a poster on the Subway to immediately donate money to a Charity. A user without a smartphone can print out a Presentation and present it to a Kiosk for access.
The following conventions are used in the design of this protocol:
The purpose of the invite
message is to publish basic
trust credentials and service capabilities of the Issuer for the purposes
of discovery and connection bootstrapping by a Holder.
This message may be static and generally available, or it may be generated in the context of a session, a transaction, or periodically.
Need to determine what belongs here and what remains the DID Document.
REQUIRED. MUST be set to a URI for the issuer. This MAY be a
URL or MAY be a DID. If the iss
is a URL, it MUST
be "https://". DIDs MAY be did:peer
DIDs or Resolvable DIDs.
How do did:key and did:web fit in here?
Using "issuer" not JOSE "iss" because issuer has specific semantics for VCs.
did:key:...
REQUIRED. An array of the supported formats of Verifiable Credential proof algorithms the issuer is able to support. This MUST contain one of:
zkp
: for zero knowledge proofs.ldsig
: for LD-Signature proofs.jws
: for inline JWS proofs.jwsd
: for detached JWS signature proofs. (is this a defined thing in v1.0? Or just LD?)REQUIRED. An array of VC-QL binding schemes this issuer supports, and their associated connection details.
Bindings may not make sense; this may be something that comes across in the DID Document.
REQUIRED. An array of credential types / schema definition DIDs. Schemas defined by URLs MUST used the
did:web:
method.
if we enforce did:web here, why not in the iss
field?
"vc-ql": { "type": "issuer-invite", "issuer" : "did:example:IiI", "enk": "did:key:z6eu48rjfdi39djdiod9de9wjwid9d", "formats" : [ "zkp", "ldsig", "jws", "jwsd" ], "bindings": [ { "scheme": "https", "params" : { "endpoint: "https://issuer.org/request"} }, { "scheme": "didcomm", "params" : { "@type" : "https://didcomm.org/didexchange/1.0/invitation", ...} }, { "scheme": "oauth3", "params" : { "txnreq" : "https://issuer.org/oauth3/req"}}, { "scheme": "js-inline"} ], "credentials": [ "did:web:https://schema.org/Person" ] }
Issuers MAY publish this invite
for general public
access, or it MAY generate specific invite
messages for given scenarios, sessions, or use cases.
How an issuer
provides this message to a Holder is out of scope for this specification,
but examples include hosting this information on a .well-known/
URL, printing a barcode Holders can scan, or providing it out of band to
Holder developers in a published API specification.
Holders that receive this message MUST process it in the following manner:
type
is "issuer-invite".
iss
by
either resolving the signing key from the DID document, or
verifying the host TLS certificate if the iss
is a URL.
enk
as an algorithm the Holder
can support and the key is valid.
proofs
list to ensure the
Holder can support at least one format. If the Holder is unable
to support at least one format, the Holder MUST inform the user
of the error and stop processing.
binding
array and find at least
one supported binding the Holder can support. If there is no
compatible binding, the Holder MUST inform the user of the error
and stop processing.
credentials
array and determine if those
Credential types are applicable for the Holder.Introduction is a request/response protocol message. Holders introduce their subjects (and possibly themselves) to the Issuer, and the Issuer MUST indicate if the introduction was accepted, rejected, or needs more information.
Holders send a issuer-introduce
message to provide
a subject identifier and associated key material for the issuer
to establish trust in the Holder.
This message MUST be a JWS. The associated "kid" MUST be a subject owned signing key related to the subject identifier provided in the message.
REQUIRED. The subject's Identifier for the Issuer and to be contained
in the Verifiable Credentials as the credentialSubject
.
Why am I using different terms then the Verifiable Credentials spec? The answer is 'brevity for low bandwidth Comm Channels' but is that valid?
sub
URI - for example,
a key defined in the DID Document.
OPTIONAL. The Holder MAY provide additional parameters in this
introduction if the Holder knows a-priori that they will be required.
If this message is in response to a previous issue-introduce-continue
result,
this object holds the required parameters to complete the introduction
(or continue negotiation).
For example, attestations as to the type of software acting as a
Holder, the contents of a did:peer
document, etc... TBD
"vc-ql" : { "type" : "issuer-introduce", "sub" : "did:example:Udid99", "aud" : "did:example:IiI", "enk" : "did:example:Udid99#key-2", "params" : { } }
Should this be "id" instead of "sub" ?
Should this be a JWE, or a JWS with the option of JWE if required?
How does this work with the concept of handles
in OAuth "3" ?
When processing this introduce
message the Issuer:
issuer-introduce
.aud
URI.kid
associated to the sub
URI.
For example, by dereferencing a DID and locating the key in the DID Document.
params
field if no additional parameters are expected.params
field, only process expected fields and MUST ignore others it does not recognize.
Issuers make a decision to proceed with the Holder based in the
contents and quality of the issuer-introduce
request.
Issuers who are ready to proceed send back an accepted
response. Issuers that need more information send back a
continue
response. Issuers that cannot proceed send
back a rejected
response.
Currently I am leaving the synchronous/asynchronous message mapping to the Comm Channel, for example the DIDComm "~thread" field.
accetped
"vc-ql": { "type" : "issuer-introduce-accepted" }
When a Holder receives an accepted
response, they
MUST use the same sub
identifier for the rest of
this Issuance session.
continue
"vc-ql": { "type" : "issuer-introduce-continue", "params" : { } }
When a Holder receives a continue
response,
the Issuer is asking for more information to bootstrap
the trust in the Holder (not necessarily the Subject!
Although in some use cases verifying the Subject may be
efficient). The params
will contain the Issuer
requirements. TBD.
Holders that are able to continue MUST re-issue a issuer-introduce
message with the continue parameters in the params
section
of the message. The Holder MUST use the same sub
URI in the
subsequent message.
Does this protocol need the concept of DIDComm threading? Ideally Comm channels can handle that...
Bootstrapping trust refers to the exchange of messages required for the Issuer and Subject/Holder to establish the required trust assurance to Issue (and accept) the Credential. A trivial example would be in the case of a driver's license:
Trust Frameworks and their governance are outside the scope of this specification. For the purposes of this specification it is sufficient to note that profiles of this protocol MUST define the requirements of how trust is established between Issuer, Holder and Subject before Issuance can occur.
Examples include the use of TLS certificates, providing Verifiable Credentials issued from a shared Trust authority, providing attestation certificates such as in [[Web AuthN]], the exchange of shared secrets or other credentials, or even in-person, physical trust establishment (like a certification sticker on a barcode reader).
This is a message for a Holder to request a credential of a certain type from an Issuer. This message is OPTIONAL in a workflow.
In workflows where a Holder is actively trying to collect credentials from Issuers and the Comm Channel allows for the Holder to reach out to the Issuer, this message MAY be used. This message MAY be used in scenarios where additional Holder to Issuer messages are required to generate the Credential, for example in Zero Knowledge Proof scenarios.
In workflows where the Issuer is interacting with the user and then offers to provide a Credential to the user's Holder, for example at a physical kiosk or a website, the Issuer may interact with the user to determine the parameters of the Credential it is willing to issue, then skip right to the Store Credential message.
Holders send a issue-credential-request
to
collect a Credential from an Issuer. Holders MAY request multiple
Credenitals in a single message.
Messages SHOULD be trusted and secured over the Comm Channel. If the Comm Channel cannot provide the acceptable level of trust and security, this message MUST be sent as a JOSE signed and/or encrypted payloads, or COSE (RFC 8152) signed and/or encrypted payload.
Holders MUST prove they are a controller of the Subject Identifiers contained in each request. This can be established through the Comm Channel, through the above JOSE/COSE payload wrappers, or through a commonly understood application level control (such as proof of a "link secret" that the Issuer understands).
How can a processing agent can easily detect if the payload is plain, jose, or cose? Do we need an object name ( "cose" : ...) or just detect string v. object... ?
Is the Link Secret in Indy a Comm Channel property? That would be nice because then it can be removed from here as it may be confusing to implementors.
issue-credential-request
.Does type
make sense with out @context
?
issuer-introduce
message, or derivable from an introduction.
Hmm, like Subject, do we need to have multiplicity here?
REQUIRED. A non-empty array of credential types the Holder is requesting.
type
field.sub
.issue-credential-params
response message."vc-ql": { "type" : "issue-credential-request", "sub" : "did:example:Udid99", "aud" : "did:example:IiI", "format" : "ld-proof", "credentials" : [ { "type" : [ "VerifiableCredential", "UniversityDegreeCredential" ], "id" : "did:example:Udid99", "params" : { } }, { "type" : [ "VerifiableCredential", "UniversityTranscriptCredential" ], "id" : "did:example:Udid99", "claims" : [ "final_gpa" ] "params" : { } } ] }
should "sub" be "id" ?
should "VerifiableCredentrial" type be implied ? its in the protocol name, after all ...
credentials may have different DIDs for privacy and unlink-ability... how does an Issuer link the DIDs "together" ?
Do we need multiplicity in the isser-introduce
message?
Issuers process the issue-credential-request
message as follows:
type
MUST be issue-credential-request
.sub
MUST be known to the Issuer through an issuer-introduce
message.aud
Issuer MUST be a controller of the identifier URI.format
.
credentials
MUST not be empty.credentials.type
MUST contain VerifiableCredential
credential.type
MUST contain only Credential schemas supported by the Issuer.credential.id
MUST be a URI controlled by the Holder and linked to the sub
.credential.claims
associated to the schema, and no more. Schema specific properly matching (i.e. beyond the property name) is outside the scope of this specification.credential.params
it does not recognize.Issuers MUST determine if there is enough "trust" in the Holder (either through this session or a previous session) to issue the requested credentials.
Issuer MUST determine if they have enough information from the Subject or Holder
to issue the credential, or if additional data is required. If the Issuer is
ready to issue the credential, it MAY respond with a issue-credential-store
response. If the Issuer requires
more information, it MAY return a issue-credential-params
response
or an issue-credential-error
response and collect more information
out-of-band from this protocol.
Issuers MUST determine if their own internal policies, and those of their trust framework, are met for Credential issuance.
This message is used by both Holders and Issuers to specify additional parameters either required or available to issue the credential.
Parameters may include cryptographic materials, additional Credentials or trust bootstrapping, user interaction or user agent parameters.
Normative params
are outside the scope of this
specification, but should they be? Do we need to define at least a
couple "useful" ones?
issue-credentials-params
."vc-ql": { "type" : "issue-credentials-params", "aud" : "did:example:Udid99", "issuer" : "did:example:IiI", "credentials" : [ { "type" : [ "VerifiableCredential", "UniversityDegree" ], "id" : "did:example:Udid99", "params" : { "myparam1" : { "type: : "present-credential-request", ... } } }, { "type" : [ "VerifiableCredential", "UniversityTranscript" ], "id" : "did:example:Udid99", "params" : { "redirect" : { "type" : "url_interaction", ... } } } ] }
The params response is another issue-credential-request with the param results provided in the same field/key. For example, "myparam1" would contain the Verifiable Presentation - "redirect" would contain the result from the URL redirect, and so on.
This message is from the Issuer to the Holder containing the issued Verifiable Credential.
This message SHOULD be trusted and secured over the Comm Channel. If the Comm Channel cannot provide enough trust or security, this message MUST be wrapped in JOSE or COSE signing and/or encryption payloads. This message MUST be encrypted directly to the Holder or the Holder's EDV.
Same issue as above on how a processing agent can easily detect if the payload is plain, jose, or cose?
vc-ql : { "type" : "issuer-store-credential" "vcs" : [ { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "UniqueIdentifierGoesHere", "type": [ "VerifiableCredential", "UniversityDegreeCredential"], "issuer": "did:example:IiI", "issuanceDate": "2010-01-01T19:73:24Z", "credentialSubject": { "id": "did:example:Udid99", "degree": { "type": "BachelorDegree", "name": "Bachelor of Science and Arts" }, "proof": { "type": "RsaSignature2018", "created": "2017-06-18T21:19:10Z", "proofPurpose": "assertionMethod", "verificationMethod": "did:example:IiI#key-1", "jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5X sITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUc X16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtj PAYuNzVBAh4vGHSrQyHUdBBPM" } } ] }
Processing agents should probably also check that the DIDs and Keys the thing was issued to match what the Holder asked for...
Holders (or EDVs) SHOULD iterate through the vcs
array
and store the associated credentials.
Do we want to include a 'revocation' field, where a previous VC ID can be indicated as 'revoked'? This would be an OPTIONAL field, and complicate the processing of these messages...
These messages are exchanged when a Verifier wishes to request a Verifiable Presentation from a Holder. These are the major steps in this process:
There is not a risk of information leakage problem here if the Verifier rejects the Holder/DID Method (i.e. receives information it will not be able to use). Any data delivered to the Verifier is subject to the Verifier's data handling processes.
A Verifier first needs to generate Verifiable Presentation request to provide to the Holder to process. The format of the request is as follows:
Unorganized notes. Verifier instead of classic JSON "iss" because "issuer" is an overloaded term. returnURI - this can be a DID or a URL -- is this part of the Comm Layer? purposeURI - did or URL with standard language. "reason" - do we really need a reason for each schema? delegated flag? using credential.name instead of ID because processing the response will be code looking for different credential types, not unique IDs.
"vq-rl" : { "type" : "verifier-request", "id" : "uuid:8D9FA614-71DC-4B4B-A243-5696FD98C408", "verifier" : "did:example:VeR66" "returnURI" : "did:example:VeR66/callback", "purposeURI" : "did:example:3483898298381/purpose1", "purposeText" : { "en_ca" : "Membership Sign Up", "en_fr" : "S'inscrire à l'adhésion" "es_mx" : "Inscripción de membresía" } "formats" : [ "zkp","ldsig" ], "genericParams" : { ... } "strict" : true "credentials" : [ { "name" : "uniqueStringAssignedByVerifier", "reason" : { "en_ca" : "Because I want it.", "en_fr" : "parce que je le veux.", "es_mx" : "Porque lo quiero" }, "issuers" : [ "did:example:3483898298381/institution_list", "did:example:IiI" ], "@context" : [ " "https://w3.org/2018/credentials/v1" ], "type" : [ "VerifiableCredential", "UniversityDegree" ], "claims" : [ "degree" ], "required" : true, "issuer_source" : true "params" : { .. }, }, { "name" : "AnotheruniqueStringAssignedByVerifier", "issuers" : [ "did:example:3483898298381/passport_issuers" ], "@context" : [ ], "type" : [ "VerifiableCredential", "Personal" ], "required" : true, } ], }
This spec does not allow for a rich query language, because it forces Holders to implement complex UIs. Verifiers either need the information they are asking for, or they have determined through a UI session what this query must contain. Verifiers own their business logic, not Holders.
In cases where the Holder requires more information from the Verifier to proceed with the Presentation. This could be parameters for the proof objects or to establish trust.
"vq-rl" : { "type" : "verifier-params", "id" : "uuid:50AD9BCF-4D88-4605-9F9B-378A939F7999", "requestId" : "uuid:8D9FA614-71DC-4B4B-A243-5696FD98C408", "genericParams" : { "myparam1" : { .. } }, "presentationParams" : [ { "name" : "uniqueStringAssignedByVerifier", "params" : { ... } }, { "name" : "AnotheruniqueStringAssignedByVerifier", "params" : { .. } } ] }
Verifiers receiving a verifier-params
response MUST re-issue
a verifier-request
with the required parameters to the Holder if
they can support the request.
This message contains the response to a Presentation Request (a
verifier-request
). In some cases "unsuccessful" responses
can be ignored, as the Verifier cannot proceed without
the required data. In other cases an unsuccessful response MAY be provided
to the Verifier for cases where the Verifier is capable of
alternate business logic and success paths.
"vr-ql" : { "type" : "verifier-response", "id" : "uuid:50768C74-0D43-431C-B735-C26F37F58AF6", "requestId" : "uuid:8D9FA614-71DC-4B4B-A243-5696FD98C408", "result" : enum ["fail", "partial", "complete"], "credentials" : [ { "name" : "uniqueStringAssignedByVerifier", "vp" : { ... }, "vpURI" : " my_edv_uri" }, { "name" : "AnotheruniqueStringAssignedByVerifier", "error" : "unavailable" } ] }
I'm sure it's fine.
Need to include the authors in these credits!