This specification describes a declarative JSON-based query language used by applications to perform requests from wallets and agents. The results of the requests are always wrapped in a Verifiable Presentation.

This draft highlights some of the pending issues that are still to be discussed in the community group. No decision has been taken on the outcome of these issues including whether they are valid. Pull requests with proposed specification text for outstanding issues are strongly encouraged.

Introduction

When working with Verifiable Credentials, Decentralized Identifier (DID) based Authentication, and Authorization Capabilities, a client application often needs to request credential-related objects from a wallet or agent. This document presents a specification that describes the format of those requests.

Note: This specification is unstable at present, and only reflects an effort to get initial interop working, for incubation and implementation experience. Additionally, the intention is to align this spec and the query format to fit into/work with other protocols/messaging formats such as DIDComm.

Overview

To make a request for one or more objects wrapped in a Verifiable Presentation, a client constructs a JSON request describing one or more queries that it wishes to perform from the receiver.

{
  query: [{
    type: 'APopularQueryType',
    // query details ...
  }, {
    type: 'AnotherQueryType',
    // query details ...
  }],

  // Challenge that will be digitally signed in the authentication proof
  // that will be attached to the VerifiablePresentation response
  challenge, // Required
  recipients: [
    // an optional key agreement key for encrypting the response if
    // this is supported
  ],
  interact: {
    // an optional set of mechanisms that can be used to respond to the query
    "service": [{
      // a service that can be used to respond to the query where the service
      // might be an HTTP endpoint, bluetooth location, or P2P protocol
    }]
  }
}
        

Terminology

This specification relies on terminology defined in [[[VC-DATA-MODEL-2.0]]]. This section defines additional terms used in this specification. A link to these terms is included whenever they appear in this specification.

presentation request
A request made by a [=verifier=] for a [=presentation=] by the [=holder=].

Query and Response Types

The query type serves as the main extension point mechanism for requests for data in the presentation. While this document defines several common query types, all query objects are of the following form:

query
A REQUIRED property that specifies the information requested by the [=verifier=]. The value MUST be one or more [=maps=] where each [=map=] MUST define a `type` property with an associated [=string=] value.
challenge
An OPTIONAL, unique [=string=] that is provided by a [=verifier=] to a [=holder=] during a specific [=presentation request=]. The [=holder=] includes the data in a [=verifiable presentation=] to the [=verifier=] to protect against replay attacks.
domain
An OPTIONAL [=string=] that is provided by a [=verifier=] to a [=holder=] during a [=presentation request=]. The [=holder=] checks to ensure that the data is associated with the domain, such as a website domain, that they are interacting with, and if it is, includes the data in a [=verifiable presentation=]. A domain is used to ensure that the [=holder=] limits their [=verifiable presentation=] to a specific [=verifier=] in order to protect against replay attacks.

Query By Example

The "query by example" credential query format is designed to enable developers to easily request the [=claims=] that they need to perform a particular business process from one or more [=verifiable credentials=]. The query can also specify other information, such as one or more [=issuers=] that are trusted by the [=verifier=].

{
  "query": [
    {
      "type": "QueryByExample",
      "credentialQuery": [
        {
          // One or more example query entries
          "required": false, // (Optional) Defaults to 'true' if omitted
          // (Optional) Reason for requesting this credential that
          // may be shown to a user by their wallet software
          "reason": "We need you to prove your eligibility to work.",
          "example": {
            "@context": ["https://www.w3.org/2018/credentials/v1", "https://w3id.org/citizenship/v1"],
            "type": "PermanentResidentCard",
            // (Optional) You can request a specific subject id
            "credentialSubject": {
              "id": "...",
              "name": "..."
            },
            // (Optional) Specify only credentials of a particular schema
            "credentialSchema": {
              "id": "urn:foo:1234",
              "type": "SomeType"
            }
          },
          // (Optional) Specify credentials from a particular issuer only
          "trustedIssuer": [
            {
              "required": true,
              "issuer": "urn:some:required:issuer"
            }
          ]
        }
      ]
    },
    {
      // Another example query
      "type": "AnotherQueryType"
      // ...
    }
  ],
  "challenge": "3182bdea-63d9-11ea-b6de-3b7c1404d57f",
  // the domain that will be digitally signed in the authentication
  // proof that will be attached to the VerifiablePresentation
  // response, identifying the recipient
  "domain": "jobs.example.com"
}
        

DID Authentication

This section defines how a verifier can request that a holder perform Decentralized Identifier-based Authentication [[?DID-CORE]]. In its simplest form, the authentication protocol is comprised of a challenge by the verifier and a response by a holder:

{
  "query": [{
    "type": "DIDAuthentication",
    "acceptedMethods": [{"method": "example"}]
  }],
  "challenge": "99612b24-63d9-11ea-b99f-4f66f3e4f81a",
  "domain": "example.com"
}
        

The DID Authentication request above specifies that the verifier would like the holder to demonstrate control over a DID by generating a digital signature over the provided challenge. The holder might respond by providing the following response:

{
  "@context": ["https://www.w3.org/ns/credentials/v2"],
  "type": "VerifiablePresentation",
  "holder": "did:example:12345",
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-rdfc-2022",
    "verificationMethod": "did:example:12345#key-1",
    "challenge": "99612b24-63d9-11ea-b99f-4f66f3e4f81a",
    "domain": "example.com",
    "created": "2024-02-25T14:58:42Z",
    "proofPurpose": "authentication",
    "proofValue": "z3FXQjecWufY46...UAUL5n2Brbx"
  }
}
        

The DID Authentication examples shown in this document use a new proof type called `DataIntegrityProof` which is currently under development in the W3C Verifiable Credentials Working Group.

The DID Authentication Query Format

The DID Authentication query format enables a verifier to request that a holder authenticate in specific ways. A DID Authentication query MUST be of the following form:

Property Description
type a REQUIRED string value that MUST be set to DIDAuthentication.
acceptedMethods An optional array of objects that expresses the verifier would accept any DID Method listed. Each object in the array MUST contain a property called `method` with a value that is a DID Method name, and MAY contain other properties that are specific to the DID Method. Valid example values include: [{"method": "key"}] and [{"method": "key"}, {"method": "web"}].
acceptedCryptosuites An optional array of objects that conveys the cryptography suites that MUST be used by the holder to generate a cryptographic proof. Each object in the array MUST contain a property called `cryptosuite` with a value that is a cryptosuite name, and MAY contain other properties that are specific to the cryptosuite. Valid example values include: [{"cryptosuite": "eddsa-rdfc-2022"}] and [{"cryptosuite": "ecdsa-rdfc-2019"}, {"cryptosuite": "bbs-2023"}].

The following example demonstrates that the verifier would like the holder to use the DID Web method and a data integrity ECDSA cryptography suite to authenticate over the established communication channel, such as the Credential Handler API (CHAPI):

{
  "query": [{
    "type": "DIDAuthentication",
    "acceptedMethods": [{"method": "key"}],
    "acceptedCryptosuites": [{"cryptosuite": "ecdsa-rdfc-2019"}]
  }],
  "challenge": "99612b24-63d9-11ea-b99f-4f66f3e4f81a",
  "domain": "example.com"
}
          

The next example demonstrates that the verifier would like the holder to use either the DID Key or DID Web method, and the standard EdDSA data integrity cryptography suite, and optionally also include a cryptographic proof that they are capable of performing a data integrity BBS proof, and authenticate over a different communication channel, in this case using a Verifiable Credential API HTTP endpoint:

{
  "query": [{
    "type": "DIDAuthentication",
    "acceptedMethods": [{"method": "key"}, {"method": "web"}],
    "acceptedCryptosuites": [{"cryptosuite": "ecdsa-rdfc-2019"}]
  }, {
    "type": "DIDAuthentication",
    "required": false,
    "acceptedMethods": [{"method": "key"}, {"method": "web"}],
    "acceptedCryptosuites": [{"cryptosuite": "bbs-2023"}]
  }],
  "challenge": "zLEwtBYgQVNR4tyeo",
  "domain": "didauth.example",
  "interact": {
    "service": [{
      "type": "UnmediatedHttpPresentationService2021",
      "serviceEndpoint": "https://didauth.example/exchanges/zYRo25k7G2UVWkrNt"
    }]
  }
}
          

The DID Authentication Response Format

The DID Authentication response format enables a holder to provide the information requested by the verifier. A DID Authentication response MUST be a verifiable presentation of the following form:

Property Description
type a REQUIRED string value that MUST be set to VerifiablePresentation.
holder a REQUIRED string value that MUST be set to a specific DID that is of the type that was requested in the DID Authentication query.
proof a REQUIRED value that MUST be one or more specific digital proof types that were requested in the DID Authentication query. Each proof object MUST include the `domain` and `challenge` values that were provided in the DID Authentication query. Holder implementations MUST ensure that the `domain` specified by the verifier matches the domain used for the current channel of communication.

It is vital that a holder implementation check the `domain` provided by the `verifier` against the domain used for the current channel of communication. If this is not done, a dishonest verifier could then replay the message to a domain that is not their own. For example, a dishonest verifier operating from the `evil.example` domain could retrieve a challenge from your bank, specify a domain value of `yourbank.example`, and then replay your response to your bank to get access to your financial accounts. This attack is mitigated as long as implementations ensure that the appropriate domain is used when generating the verifiable presentation.

The example below demonstrates a simple DID Authentication response.

{
  "@context": ["https://www.w3.org/ns/credentials/v2"],
  "type": "VerifiablePresentation",
  "holder": "did:example:12345",
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-rdfc-2022",
    "verificationMethod": "did:example:12345#key-1",
    "challenge": "99612b24-63d9-11ea-b99f-4f66f3e4f81a",
    "domain": "example.com",
    "created": "2024-02-25T14:58:42Z",
    "proofPurpose": "authentication",
    "proofValue": "z3FXQjecWufY46...UAUL5n2Brbx"
  }
}
        

Authorization Capability Request

This query type would be included in a request to ask for Authorization Capabilities or "zcaps" in the Verifiable Presentation.

{
  query: [{
    type: 'ZcapQuery',
    capabilityQuery: [{
      referenceId: `a-memorable-name`,
      allowedAction: ['read', 'write'],
      invoker: 'did:key:1234',
      delegator: 'did:key:1234'
      invocationTarget: {
        type: 'urn:edv:documents'
      }
    }, {
      referenceId: `another-memorable-name`,
      allowedAction: 'sign',
      invoker: 'did:key:1234',
      delegator: 'did:key:1234',
      invocationTarget: {
        type: 'Ed25519VerificationKey2018',
        proofPurpose: 'assertionMethod'
      }
    }],
    challenge: '111112b24-63d9-11ea-b99f-4f66f3e4f81a'
  }]
}
        

Logical Operations in Queries

In Verifiable Presentation Requests, the structuring and retrieval of information rely on the use of logical operations. "AND" and "OR" operations play crucial roles in defining the path to desired data.

Top-Level Queries ("AND" Operation)

At the top-most level of the request structure, different types of queries are expected to be processed as "AND" operations. Each query is a unique condition that needs to be met to fulfill the request. This means, each query listed in the top-level array is an independent requirement.

In this example, there are two queries: `APopularQueryType` and `AnotherQueryType`. The "AND" operation here indicates that both these conditions need to be met in order to fulfill the request.

{
  "query": [
    // "and"
    {
      "type": 'APopularQueryType',
      // query details ...
    },
    // "and"
    {
      "type": 'AnotherQueryType',
      // query details ...
    }
  ]
}
        

Nested Queries ("OR" Operation)

Within a specific query type, an "OR" operation can be defined. This operation indicates that one or more of the nested conditions needs to be met. When all credentialQuery objects are optional, they are interpreted as "OR" operations within their context. This enables flexible and forgiving data retrieval where optional conditions can refine the results when possible, but their absence will not halt the process.

In this `QueryByExample` type, we have a `credentialQuery` array where all queries are optional. The "OR" operation suggests that fulfilling any one of the listed conditions within `credentialQuery` will enhance the results, but is not a requirement for the request to be valid or fulfilled. If none of the optional `credentialQuery` conditions are met, the request will still proceed with the other conditions outside the `credentialQuery` scope, which are interpreted with an "AND" operation.

{
  "query": [
    // "and"
    {
      "type": "QueryByExample",
      "credentialQuery": [
        // "or"
        {
          "required": false,
          ...
        },
        // "or"
        {
          "required": false,
          ...
        },
      ]
    },
    // "and"
    { ... }
  ]
}
        

Interaction Types

The interaction type serves as the main extension point mechanism for ways of responding to a query.

Mediated Presentation

A mediated presentation service requires the use of an out-of-band interface, for example, a person using a Web browser.

...
"interact": {
  "service": [{
    "type": "MediatedBrowserPresentationService2021",
    "serviceEndpoint": "https://degree.example/fill-out-forms?session=123456"
  }]
}
...
        

OIDC Credential Provider

A mediated presentation service that utilizes the Open ID Connect Credential Provider interaction mechanism.

...
"interact": {
  "service": [{
    "type": "OpenIdConnectCredentialProviderService2021",
    "serviceEndpoint": "https://degree.example/authorize?response_type=code&scope=openid%20openid_credential&client_id=s6BhdRkqt3&state=af0ifjsldkj&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb&credential_format=w3cvc-jsonld"
  }]
}
...
        

DIDCommv2 Presentation

A mediated presentation service that utilizes the DIDCommv2 interaction mechanism.

...
"interact": {
  "service": [{
    "id": "did:example:123456789abcdefghi#didcomm-1",
    "type": "DIDCommMessaging",
    "serviceEndpoint": {
      "uri": "http://example.com/path",
      "accept": [
        "didcomm/v2",
        "didcomm/aip2;env=rfc587"
      ],
      "routingKeys": ["did:example:somemediator#somekey"]
    }
  }]
}
...
        

Unmediated Presentation

An unmediated presentation service requires no out-of-band interfaces, enabling fully-automated presentation processing.

...
"interact": {
  "service": [{
    "type": "UnmediatedHttpPresentationService2021",
    "serviceEndpoint": "https://degree.example/active-flows/123456"
  }]
}
...
        

Usage Scenarios

This request query format is intended to be used in a variety of protocols and usage scenarios.

Browser - Credential Handler API (CHAPI)

The Credential Handler API (CHAPI) specification enables in-browser Javascript applications to communicate with wallet providers for the purpose of issuing Verifiable Credentials and requesting Verifiable Presentations. Interested implementers are encouraged to look at the Credential Handler Polyfill repository for further discussion and examples.

CHAPI is an extension of the Credential Management API, and includes the following:

A VerifiablePresentation is used to both store or present VerifiableCredentials. When storing a VerifiableCredential, the VerifiablePresentation does not need to be signed.

WebCredential

CHAPI provides a single derived class, the WebCredential that forms the basis for any sort of credential data that is provided over the Web, i.e., via a "Credential Handler" that a origin has registered in the user's browser when the user visited that origin's website. Note that CHAPI provides an optional recommendedHandlerOrigins feature for any credential storage request to allow a Relying Party (aka issuer) to suggest one or more digital wallets to help the user store the credential. This is particularly helpful if the user has no wallet yet. The listed origins must have a `manifest.json` file with a valid `credential_handler` entry in order to be used by CHAPI.

// optionally include `recommendedHandlerOrigins` so the user can choose an
// applicable wallet if they don't have one yet:
const options = {
  recommendedHandlerOrigins: [
    'https://wallet.example'
  ]
};
const webCredential = new WebCredential('VerifiablePresentation', {
  '@context': 'https://www.w3.org/2018/credentials/v1',
  ...presentation,
  options
});
          

Requesting and Storing Credentials

Using CHAPI, 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).

get()

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. Note that CHAPI provides an optional recommendedHandlerOrigins feature for any credential request (not specific or restricted to VPR) to allow a Relying Party (aka verifier) to suggest one or more digital wallets to help the user complete the request. This is particularly helpful if the user has no wallet yet. The listed origins must have a `manifest.json` file with a valid `credential_handler` entry in order to be used by CHAPI.

const credentialQuery = {
  web: {
    VerifiablePresentation: {
      query: {
        type: 'QueryByExample',
        credentialQuery: {
          // an optional reason for requesting this credential that
          // may be shown to a user by their wallet software
          reason: 'We need you to prove your eligibility to work.',
          example: {
            '@context': [
              'https://www.w3.org/2018/credentials/v1',
              'https://w3id.org/citizenship/v1'
            ],
            type: 'PermanentResidentCard'
          }
        }
      },
      // a 128-bit randomly generated value encoded as a string (use a UUID);
      // it will be digitally signed in the authentication proof
      // that will be attached to the VerifiablePresentation response
      challenge: '3182bdea-63d9-11ea-b6de-3b7c1404d57f',
      // the domain that must be digitally signed in the authentication
      // proof that will be attached to the VerifiablePresentation
      // response, identifying the recipient
      domain: 'jobs.example.com'
    },
    // optionally include credential handler origins to recommend to
    // the user if they have no wallet or may want to choose one
    // the RP recommends; this is an optional CHAPI feature, it is not
    // specific to VPR
    recommendedHandlerOrigins: [
      'https://wallet.example'
    ]
  }
};
const webCredential = await navigator.credentials.get(credentialQuery);

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

// Response:

null // if the user cancels

// or a WebCredential with these attributes/values:
{
  "type": "web",
  "dataType": "VerifiablePresentation",
  "data": {
    // Verifiable Presentation goes here, containing the credentials
    // that the user agreed to share
  }
}

const {data: presentation} = webCredential;
// send `presentation` to server for forwarding to verifier API
          
// requesting DID Authentication that can be performed at the given `interact`
// service endpoint; the endpoint may respond to the DID Authentication
// response with another VPR or a VP with credentials
const credentialQuery = {
  web: {
    VerifiablePresentation: {
      query: {
        "type": "DIDAuthentication",
        "acceptedMethods": [{"method": "example"}]
      },
      challenge: '3182bdea-63d9-11ea-b6de-3b7c1404d57f',
      domain: 'jobs.example.com',
      interact: {
        service: [{
          type: "UnmediatedPresentationService2021",
          serviceEndpoint: "https://example.edu/exchangers/z238348134/exchanges/z872347234"
        }]
      }
    },
    // optionally include credential handler origins to recommend to
    // the user if they have no wallet or may want to choose one
    // the RP recommends; this is an optional CHAPI feature, it is not
    // specific to VPR
    recommendedHandlerOrigins: [
      'https://wallet.example'
    ]
  }
};
const webCredential = await navigator.credentials.get(credentialQuery);

if(!webCredential) {
  console.log('user canceled');
}

// Response:

null // if the user cancels

// or a WebCredential with these attributes/values:
{
  "type": "web",
  // wallet responded to the request out-of-band
  "dataType": "OutOfBand",
  "data": null
}
          

store()

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.

const result = await navigator.credentials.store(webCredential);
if(!result) {
  console.log('store credential operation canceled');
}

// Response:

null // if the user cancels

// or a WebCredential with these attributes/values:
{
  "type": "web",
  "dataType": "VerifiablePresentation",
  "data": {
    // Verifiable Presentation goes here, optionally containing the
    // credentials that the user agreed to store (can be an empty
    // presentation or `null`, but this does not indicate cancelation)
  }
}
          

Security and Privacy Considerations

There are a number of security and privacy considerations that implementers will want to take into consideration when implementing this specification.

Consideration

TBD

Acknowledgements

The Working Group would like to thank the following individuals for reviewing and providing feedback on the specification (in alphabetical order):

TBD...