Indexing and Querying Revoked Verifiable Credentials

Due to its immutability and censorship resistance, the Blockchain seems to be a suitable place to manage identities and credentials. However, querying the data on the blockchain in a trusted and efficient way is one of the most challenging issues every Web3 developer has to face while developing a DApp. Therefore, this article describes a simple approach to revoke verifiable credentials and a decentralized and efficient way to index and query those revoked credentials using the Graph protocol.

We consider the knowledge of Self-Sovereign Identity (SSI) and rudimentary knowledge of the Ethr DID method as a requirement for understanding this article.

Ethr DID and Credentials

The Ethr DID method uses Ethereum addresses as identifiers. By default, the DID of the issuer/subject does not require an on-chain registration and it is constructed from the Ethereum address and controlled by its private key. This feature minimizes the effort of integrating identities in many on-chain use cases.

When an off-chain verifiable credential is created, the issuer entity must set the “issuer” property to its Ethr DID and the “credentialSubject.id” property to the Ethr DID of the subject. Example:

"verifiableCredential": {
"@context": [,]
}, "issuer": {
"id": " did:ethr:0xf1232f840f3ad7d23fcdaa84d6c66dac24efb198 "
},
"issuanceDate": "2022-07-2T12:00:00.000Z",
"credentialSubject": {
"id":"did:ethr:0x435df3eda57154cf8cf7926079881f2912f54db4",
"degree": "Bachelor Of Arts
},
{ "proof": { ... }
}

After that as usual the issued credential will be used by the subject to generate a verifiable presentation. The verifier will verify the presentation and accept or reject it depending on its business logic.

Credential Revocation

Verifiable credentials are similar to certificates, some of them have an expiration date and some don’t. However, in both cases, the issuer and the subject must be able to revoke them. To enable this critical requirement, we need a tamper-proof revocation data registry that is always available and cannot be censored by any of the mentioned parties. This can be achieved using the Blockchain. Such a registry can be implemented as a simple smart contract that stores a reference of the credential and a reference of the entity who revoked it.

The revocation process:

  • Get the hash value of the issued verifiable credential using the keccak256 hash function after converting the credentials to bytes. This value will be used as the on-chain reference to the credential
  • Send a transaction to the revocation smart contract to call the revoke method revoke(bytes32 digest)giving the extracted hash value as input
  • The entity that revoked the credential is the address of the invoker and it can be matched with the issuer or subject of the credential based on their DIDs

The additional important key that will help indexing those revocations is that when a credential is revoked, the revocation smart contract triggers an event that includes the keccak256 hash of that credential and the address of the entity that revoked it.

In the Github repository, we prepared a simple project that:

  • Deploys a revocation smart contract that stores references to the credential and the entity that revoked it.
  • Uses the did-jwt-vc and ethr-did libraries to issue 3 off-chain verifiable credentials by 3 different issuers and revoke them on-chain

Please check the./ssi-contracts folder and follow the instructions in the README file. After following the steps you should have the address of the revocation registry smart contract deployed on the Goerli network. The 3 revoked transactions can be found on Etherscan using the address of the deployed contract.

Why do we need to index the revoked credentials?

In a verification scenario, the verifier gets a verifiable presentation that includes 1 to n verifiable credentials from the subject. In addition to the normal validation process of the credentials, the verifier must also check the on-chain status of the credential at any time easily and efficiently. To do that the verifier could request the status of each credential by calling the methodrevoked(address issuer, bytes32 digest) in the revocation registry contract. However, this approach of getting the information is limited, costly, and not efficient for many reasons, some of which are:

  • It requires knowledge of the Blockchain and Web3 technology
  • It is slow and limited because of the latency, number of requests, node capability
  • It requires running a blockchain node or relaying on a node provider
  • Duplicate requests for the same credentials are sent over and over again
  • It requires the verifier to be online all the time

And this is when indexing comes into play to provide an easy, fast and simple way to iterate and query data. Indexing is especially needed in the Blockchain area where its underlying design makes it difficult to search for relevant data.

But How can we index the Blockchain?

One approach is iterating all transactions and checking if the transaction interacts with our revocation contract. This method is very slow and resource-intensive. The other approach which is used by most developers is to subscribe to events that are triggered by the target contract. This method is much easier, supported by tools and libraries like web3js, and is more resource-saving. Now we come to the second important question of who should do the indexing? There are some possible answers:

1. the verifier itself. But it is not a good solution because each verifier needs to build up and maintain its own logic and infrastructure. Furthermore, the server of the verifier that is responsible for the indexing is a single-point-of-failure

2. external ingestion service that indexes the data on behalf of the verifier. Such a service could be very useful. However, it creates one of the most critical issues which is the lack of TRUST . Verifiers need to trust the ingestion service and relying on it eliminates the advantage of using the Blockchain

3. decentralized indexing protocol like The Graph protocol, which enables decentralized applications to query complex data from the blockchain without having to develop and operate proprietary indexing servers or use a centralized service provider. This is the preferred solution in most use cases because:

  • It is distributed and decentralized. Therefore it removes the single-point-of-failure and the missing trust issue
  • It does not require advanced Web3 knowledge. Developers use only GraphQL requests to query the data from already implemented and indexed subgraphs
  • The technology behind it has been designed specifically for the Blockchain. Therefore, it is quick and easy to query and filter
  • Cost-efficient because indexers are competing with each other to provide the best service for the lowest price
  • Can be used by many verifiers around the world with minimal latency because the nodes are distributed and public

The creators of the Graph protocol recognized the indexing and querying problem at the end of 2017 and started working to solve it by defining and implementing a decentralized indexing protocol. The introduction page of the Graph protocol offers detailed information about the protocol and you can also join the free and very useful courses provided by The Graph Academy .

Develop and Deploy a Revocation Subgraph

A subgraph defines which data should be indexed from a blockchain, and how it should be stored. In our simple example, the core data the verifier requires is the hash of the credential and who revoked it. To make things easier for verifiers we could also add the timestamp and block number.

To keep the article simple we will deploy the subgraph on a hosted service. Hosted service can be seen today as a good and easy place to start with the development of Subgraphs because it is free to use and reduces the deployment and testing complexity of Subgraphs. Developers can at any time migrate their Subgraphs to the decentralized network.

The following steps to develop and deploy the Subgraph are described in detail with all the related files in this repository:

  • First, initialize a new sample project using the graph cli
  • Then modify some of the configurations like adding a startBlock and checking the address of the contract
  • After that comes the main part of the development which is to define the entities and implement the handle method that will be executed when an event is emitted by a smart contract.
  • In the end, build the project and deploy it on the hosted service using the graph cli and an access token

When the Subgraph is deployed and synchronized we can query the indexed data using simple GraphQL requests.

Example: open https://api.thegraph.com/subgraphs/name/<github-name>/credential-revocation-graph in browser and run the following query to get the hashes of all credentials that are revoked by Issuer-A from ./ssi-contracts

Query revoked credentials by an issuer

The results should contain only a single revoked credential unless you modified the scripts inside ./ssi-contract or used an already existing contract for this query. You can also compare the results with the logged data of the executed script in./ssi-contract

Summary

In this article, we described one of many approaches on how to revoke issued credentials. This outlined approach benefits from the Ethr DID characteristic and it depends on the Blockchain as an immutable registry accessible for all parties. We also talked about the likely best way to index and query revoked credentials without relying on centralized services. And at the end, we showed how to develop a simple Subgraph that could run on the Graph protocol decentralized indexing network and index the required data.

Follow us on Medium