We refreshed our doc site!
Bookmarked links may have changed
Read release notesThis tutorial demonstrates:
Verite's revocation implementation uses the approach described in W3C Status List 2021 -- a highly compressible, privacy-promoting approach.
In this method, the revocation status of a given verifiable credential is stored in a specified index of a bitstring. If the value is 0, the credential is not revoked; otherwise it's revoked.
Note: Deployments of this approach vary, and this project uses a simple REST endpoint to serve the bitstring.
Then, at verification time, a verifier obtains the entire bitstring and looks up the value at the index specified in the credential to determine whether it's been revoked.
This has the advantage that, even if the issuer is consulted for the bitstring, the verifier doesn't tell the issuer exactly which index it is checking, enabling what's called "herd privacy".
Below is an example from Status List 2021 demonstrating what a Revocable Credential might look like (in JSON-LD format, for clarity). Note the addition of credentialStatus
object with several fields:
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/vc-status-list-2021/v1"
],
"id": "https://example.com/credentials/23894672394",
"type": ["VerifiableCredential"],
"issuer": "did:example:12345",
"issued": "2021-04-05T14:27:42Z",
"credentialStatus": {
"id": "https://dmv.example.gov/credentials/status/3#94567",
"type": "StatusList2021Entry",
"statusPurpose": "revocation",
"statusListIndex": "94567",
"statusListCredential": "https://example.com/credentials/status/3"
},
"credentialSubject": {
"id": "did:example:6789",
"type": "Person"
},
"proof": { ... }
}
The presence of this object tells verifiers that they should check the credential for its current status, and where/how to do it. Specifically:
statusListCredential
is the URI from which the revocation list should be retrievedstatusListIndex
indicates which index in the bitstring this credential corresponds toStatusList2021Entry
informs verifiers the data structure to expect and steps to use to check whether the credential has been revokedThe issuer must decide at creation time whether the credential should be revocable, because the credentialStatus
property will needed to be added to the issued verifiable credential.
Suppose the following:
url
is the URL where the bitstring revocation list will be accessibleindex
is the index within the bitstring storing the specific credential's revocation statusThen credentialStatus
can be populated as follows:
const credentialStatus: {
id: `${url}#${index}`,
type: "StatusList2021Entry",
statusPurpose: "revocation",
statusListIndex: index.toString(),
statusListCredential: url
}
When issuing the credential, the issuer would pass credentialStatus
as follows:
const encoded = await composeVerifiableCredential(
issuer,
subject.id,
attestation,
{ credentialStatus }
)
A complete example follows:
// We will create a random did to represent our own identity wallet
const subject = randomDidKey(randomBytes)
// Stubbed out credential data
const attestation: KYCAMLAttestation = {
type: "KYCAMLAttestation",
process: "https://verite.id/definitions/processes/kycaml/0.0.1/usa",
approvalDate: new Date().toISOString()
}
const credentialType = "KYCAMLCredential"
/**
* Assume the credential's index within the bitstring will be 0
*/
const credentialStatus = {
id: `${revocationListUrl}#0`,
type: "StatusList2021Entry",
statusPurpose: "revocation",
statusListIndex: "0",
statusListCredential: `${revocationListUrl}`
}
// Generate the signed, encoded credential
const encoded = await composeVerifiableCredential(
issuer,
subject.id,
attestation,
credentialType,
{ credentialStatus }
)
In a real implementation, an issuer may want to maintain multiple revocation status lists. See revocation best practices for details.
When an issuer needs to revoke a credential, the bitstring approach requires the credential's index within the bitstring to be flipped to 1. Verite libraries expose a convenience method for issuers, as follows:
statusList = await revokeCredential(credential, statusList, signer)
Verite similarly exposes unrevokeCredential
to undo the revocation. Unrevoking doesn't have to be supported by issuers; some issuers choose to issue a new credential instead.
In a deployment, the revoking and unrevoking operations could be exposed by authenticated API calls that would be accessed by an authorized party, such as a compliance agent.
Note that revoking a credential doesn't change the subject's credential or the revocation list itself since both are immutable. A new, modified revocation list is built, which the party hosting the revocation list will need to persist for future lookups.
The credential itself will inform a verifier whether the credential's status needs to be checked and how. A revocable Verite credential will have a credentialStatus
field of type RevocationList2021Status
, which informs the verifier how to proceed.
At verification time, the verifier will fetch the content at the revocationListUrl
. This content will be a verifiable credential, of type "StatusList2021Credential"
, which contains the bitstring at the credentialSubject.encodedList
property (zlib-compressed, base64-encoded). See StatusList2021Credential for additional details.
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/vc-status-list-2021/v1"
],
"id": "https://example.com/credentials/status/3",
"type": ["VerifiableCredential", "StatusList2021Credential"],
"issuer": "did:example:12345",
"issued": "2021-04-05T14:27:40Z",
"credentialSubject": {
"id": "https://example.com/status/3#list",
"type": "StatusList2021",
"statusPurpose": "revocation",
"encodedList": "H4sIAAAAAAAAA-3BMQEAAADCoPVPbQsvoAAAAAAAAAAAAAAAAP4GcwM92tQwAAA"
},
"proof": { ... }
}
The verifier then inspects the credential's index in the bitstring to determine if it's revoked.
Verite exposes a helper function isRevoked
:
await isRevoked(credential, statusList)