We refreshed our doc site!
Bookmarked links may have changed
Read release notesThis guide is written for developers seeking to integrate the "wallet-bound" Verite flows and data models into custodial or non-custodial wallets. What follows is best understood as a checklist for adding "identity wallet" capabilities (handling Verifiable Credentials natively and as flexible as built-for-purpose identity wallets do) to an existing mobile wallet, whether non-custodial, custodial, or semi-custodial (MPC, multi-sig, etc).
Verite uses a decentralized identity architecture, in which the individual (subject/holder) directly requests and receives credentials from an issuer, storing them in a wallet that governs a unique and long-lasting DID. In this model, individuals decide when and with whom they want to share their credentials, referred to as verifiers, or more generally, relying parties. In some architectures and use-cases, these counterparties may know the wallet and its user only by a DID, or by a DID and the contents of credentials managed by the wallet.
The relying party verifies the credential, without necessarily needing to contact the issuer, through an extensible mechanism enabled by the VC specification. The verification process is designed to be maximally privacy-respecting and cryptographically secure.
Verite's basis is the W3C Verifiable Credentials (VCs) Data Model. A credential is a claim made by an issuer about an individual (subject), and a verifiable credential is a cryptographically secure wrapper around that credential enabling verification and handling by common, standards-based libraries such as JWT tooling.
Following is a list of concepts used in Verite.
See the list of specifications and spec-conforming libraries used by Verite.
The credential flows demonstrate use of a non-custodial credential and identifier wallet, but are easily adapted to hosted wallets, combination crypto+identity wallets, and various variations on the described flow. See the wallet-bound variants of the issuance and verification flow sections elsewhere in the docs for context.
This flow enables a subject to send prerequisite information to the issuer before credential issuance. Prerequisites include:
The process is initiated by the wallet holder scanning a QR code, which allows the wallet to determine the input requirements, asking for consent before sending (typically including cryptographically signed proof). The issuer validates the request, issues a credential to the identifier specified by the subject, and returns the credential
This flow is based on the DIF wallet and credential interaction (draft) specification, which enables use of links or QR codes for wallet-initiated interactions.
challengeTokenUrl
:
{
"challengeTokenUrl": "https://verite.id/..."
}
GET {{challengeTokenUrl}}
{
"id": "4487e7d1-7d10-4075-a923-bae9332266c1",
"type": "CredentialOffer",
"from": "did:key:z6Mkgw8mPijYRa3TkHSYtQ4P7S2HGrcJBwzdgjeurqr9Luqb",
"created_time": "2021-09-14T01:22:05.816Z",
"expires_time": "2021-10-14T01:22:05.816Z",
"reply_url": "https://...",
"body": {
"challenge": "d273da29-74dd-46de-a53c-1677c51cc700",
"manifest": {}
}
}
createCredentialApplication
for this purpose -- this is used by demo-wallet in preparing a credential application.POST {{replyUrl}}
This flow enables a verifier or relying party to request credentials and proof requirements from the subject/holder.
The process is initiated by the wallet holder scanning a QR code, which allows the wallet to determine the credential/proof requirements, asking for consent before sending (typically including cryptographically signed proof).
This flow is based on the DIF wallet and credential interaction (draft) specification, which enables use of links or QR codes for wallet-initiated interactions.
The exchange flow similarly initiates with the credential holder performing a QR scan. See message samples in Presentation Exchange
This section contains examples of the messages referenced above.
Credential subjects initiate credential issuance flows by scanning a QR code, provided by the issuer, with their credential wallet.
Sample:
{
"challengeTokenUrl": "https://verite.id/..."
}
An issuer credential offer tells the wallet how to initiate a credential issuance request. It is a simple JWM wrapper around a DIF Credential Manifest.
Sample:
{
"id": "4487e7d1-7d10-4075-a923-bae9332266c1",
"type": "CredentialOffer",
"from": "did:key:z6Mkgw8mPijYRa3TkHSYtQ4P7S2HGrcJBwzdgjeurqr9Luqb",
"created_time": "2021-09-14T01:22:05.816Z",
"expires_time": "2021-10-14T01:22:05.816Z",
"reply_url": "https://...",
"body": {
"challenge": "d273da29-74dd-46de-a53c-1677c51cc700",
"manifest": {}
}
}
Details:
A credential application is sent from the wallet to the issuer before issuance. It contains the recipient identifier and other information required for issuance. This follows the DIF Credential Manifest Spec.
What follows is a JSON object containing the same contents as a Verifiable Presentation in JWT form; there is no proof object, because it would be signed and transmitted as a JWT.
{
"@context": ["https://www.w3.org/2018/credentials/v1"],
"credential_application": {
"id": "2ce196be-fcda-4054-9eeb-8e4c5ef771e5",
"manifest_id": "KYCAMLManifest",
"format": {
"jwt_vp": {
"alg": ["EdDSA"]
}
}
},
"presentation_submission": {
"id": "b4f43310-1d6b-425d-84c6-f8afac3fe244",
"definition_id": "ProofOfControlPresentationDefinition",
"descriptor_map": [
{
"id": "proofOfIdentifierControlVP",
"format": "jwt_vp",
"path": "$.holder"
}
]
},
"verifiableCredential": [],
"holder": "did:key:z6MkjFFeDnzyKL7Q39aNs1piGo27b12upMf1MmSDQcABJmmn",
"type": ["VerifiablePresentation", "CredentialApplication"]
}
What follows is a JSON object containing the same contents as a Verifiable Presentation in JWT form; there is no proof object, because it would be signed and transmitted as a JWT.
{
"@context": ["https://www.w3.org/2018/credentials/v1"],
"type": ["VerifiablePresentation", "CredentialResponse"],
"holder": "did:key:z6Mkgw8mPijYRa3TkHSYtQ4P7S2HGrcJBwzdgjeurqr9Luqb",
"credential_fulfillment": {
"id": "5f22f1ea-0441-4041-916b-2504a2a4075c",
"manifest_id": "KYCAMLManifest",
"descriptor_map": [
{
"id": "KYCAMLCredential",
"format": "jwt_vc",
"path": "$.verifiableCredential[0]"
}
]
},
"verifiableCredential": [] // Credential would be found here, as a JWT, i.e. ["eyJhbG..."]
}
The following represents the intermediate form of a JWT-encoded verifiable credential post-verification and post-decoding to restore the "credential" (i.e., combining fields from both the payload and the protected headers of the JWT token):
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
{ "@vocab": "https://verite.id/identity/" }
],
"type": ["VerifiableCredential", "KYCAMLCredential"],
"credentialSubject": {
"KYCAMLAttestation": {
"type": "KYCAMLAttestation",
"process": "https://verite.id/definitions/processes/kycaml/0.0.1/usa",
"approvalDate": "2021-09-14T02:00:07.540Z"
},
"id": "did:key:z6Mkjo9pGYpv88SCYZW3ZT1dxrKYJrPf6u6hBeGexChJF4EN"
},
"issuer": {
"id": "did:web:verite.id"
},
"credentialStatus": {
"id": "http://192.168.1.16:3000/api/revocation/05c74310-4810-4ec4-8402-cee4c28dda91#94372",
"type": "StatusList2021Entry",
"statusPurpose": "revocation",
"statusListIndex": "94372",
"statusListCredential": "http://192.168.1.16:3000/api/revocation/05c74310-4810-4ec4-8402-cee4c28dda91"
},
"issuanceDate": "2021-09-14T02:00:07.000Z"
}
Credential holders initiate credential exchange flows by scanning a QR code, provided by the verifier, with their credential wallet.
Sample:
{
"challengeTokenUrl": "https://verite.id/..."
}
{
"id": "1308e77f-9ab0-4de7-97a8-ad2111b585bf",
"type": "VerificationRequest",
"from": "did:key:z6MkizuwMHiYpZrBAn64ZnbS2cz5og7iGqAa3nV3EuTj4aaZ",
"created_time": "2021-09-14T20:19:32.655Z",
"expires_time": "2021-10-14T20:19:32.655Z",
"reply_url": "http://192.168.1.16:3000/api/verification/1308e77f-9ab0-4de7-97a8-ad2111b585bf/submission",
"body": {
"status_url": "http://192.168.1.16:3000/api/verification/1308e77f-9ab0-4de7-97a8-ad2111b585bf/callback",
"challenge": "e0e52794-7889-451c-bb05-28d8cff9ed13",
"presentation_definition": {
"id": "KYCAMLPresentationDefinition",
...
}
}
}
Details:
Note: In the Presentation Object that follows (a signed VP in JWT form), the verifiableCredential
object contains one signed verifiable credentials. For clarity & exemplarity, a non-JWT expression in JSON-LD format is included, but the same credential, expressed as a JWT as it is in the rest of this guide, could be substituted for it in JWT format, i.e. verifiableCredential": ["eyJhbGc..."]
. JSON-LD and JWT credentials could even be combined, if the relying party was expecting multiple VCs and processed both kinds, i.e. verifiableCredential": ["eyJhbGc...", {"@Context":..."proof":...}]
.
{
"@context": ["https://www.w3.org/2018/credentials/v1"],
"presentation_submission": {
"id": "d885c76f-a908-401a-9e41-abbbeddfe886",
"definition_id": "KYCAMLPresentationDefinition",
"descriptor_map": [
{
"id": "KYCAMLCredential",
"format": "jwt_vc",
"path": "$.presentation.verifiableCredential[0]"
}
]
},
"verifiableCredential": [
{
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": ["VerifiableCredential", "KYCAMLCredential"],
"credentialSubject": {
"id": "did:key:z6Mkjo9pGYpv88SCYZW3ZT1dxrKYJrPf6u6hBeGexChJF4EN",
"KYCAMLAttestation": {
"type": "KYCAMLAttestation",
"process": "https://verite.id/definitions/processes/kycaml/0.0.1/usa",
"approvalDate": "2021-09-14T02:00:07.540Z"
}
},
"issuer": {
"id": "did:web:verite.id"
},
"proof": {...}
}
]
}
{
"status": "approved"
}