Hyperledger Aries ACA-Py Agents Setup and Running Tutorials — Part VI — Credential request, Issuance and Reception

Dr. Yunxi Zhang
8 min readMay 16, 2021

Introduction

In Part I, I’ve introduced the general benefits of using SSI and why Hyperledger Indy and Aries can fit in the big picture. In Part II, a scenario overview and tools were described. Part III shows details on how to set up a Dev environment to run an ACA-Py agent V0.6.0. In Part IV, it focused on the one-time agent level connection channel establishment. Part V described how to create a credential schema as well as its relevant credential definition. This Part VI will show how a holder can request a new credential from an issuer, who will then issue a new credential to the holder as per holder’s request, so the holder can receive the newly issued credential from the issuer.

General Process Overview

There are a few steps involved to enable the holder to get a newly issued credential from the issuer.

Step 1: holder -> requester: the holder requests a credential proposal to the requester specifying what attributes and values of a credential needed.

Step 2: requester -> holder: the holder returns a credential proposal response (aka a bound credential offer in ACA-Py world) to the requester showing what a potential credential it can issue to the requester.

Note: Steps 1 and 2 can repeat many times until a requester is happy with a credential from the holder.

Step 3: requester -> holder: the requester sends an official credential request to the issuer.

Step 4: holder -> requester: the holder sends a newly issued credential to the requester.

Step 5: requester stores the issued credential to its own wallet.

To make below steps to work, the agent-level connection and the credential schema and definition must have been done properly. Please make sure you have followed all the pre steps in my blog.

Step 1: Requester sends a credential proposal

You can now call a POST API named: /issue-credential-2.0/send-proposal on the holder agent. The JSON body is quite long, you could quickly copy the sample body from the holder agent’s Open API (figure 1).

figure 1 — API for sending a credential proposal

The bit we need to change in the JSON sample body are mainly the key/value pair as shown below.

“connection_id”: the connection id used by the holder agent that can communicate with the issuer agent.

a list of “name” and “value” pairs inside the “attributes” block which is inside the “credential_preview” block: the value of each “name” MUST match each of the attribute type defined in the credential schema; the value of each “value” should be a proper value we expect for each “name”.

In our case, we have defined three attributes in the passport credential: (1) lastname (2) firstname and (3) age. The value I put for each are: (1) Peter (2) Pan and (3) 14 as used in the example given in Part V. Below shows the two changes in the JSON body (see figures 2 and 3).

figure 2 — connection_id used by the holder agent
figure 3— key/value pairs used in the “attributes” block used by the holder agent

Once successful, a long JSON payload will be returned. Figure 4 only shows an excerpt. We can see the “state” attribute shows this proposal has been sent. In the “credential_preview” section, it shows how a credential would look like, which is exactly the same as how we put in the JSON body for calling the API.

figure 4 — response after calling sending a credential proposal

Step 2: Issuer returns a credential proposal response

Once the previous step is done, we can switch to the issuer agent side to issue a new credential as requested by the holder.

Before issuing a new credential, the issuer has to figure out what is requested from the holder.

You can now call a GET API named: /issue-credential-2.0/records on the issuer agent to get all the credential proposals. Figures 5 and 6 show excerpts of the API response. Line 23 in figure 5 shows a proposal is received as reflected in a “status” field. Lines 37 to 47 shows an example credential requested by the requester.

figure 5 — holder checks credential proposal requests

Note: note down the value of the field “cred_ex_id” somewhere as shown in line 30 in figure 5, as we will need it for the following steps for the issuer. In my case, the value is f7e30b9b-b740–41f7–8007–75113e432bf6.

Assuming the issuer has checked the proposed credential and agrees to issue such an a credential to the holder.

You can now call a POST API named: /issue-credential/records/{cred_ex_id}/send-offer on the issuer agent. The JSON body is also quite long, you could quickly copy the sample body from the holder agent’s Open API (figure 6).

figure 6— API for the issuer to send a confirmation response to the credential proposal

In the url, replace the {cred_ex_id} with the value noted down just now. So, in my case, the url is: /issue-credential/records/f7e30b9b-b740–41f7–8007–75113e432bf6/send-offer.

The bit we need to change in the JSON sample body are mainly the key/value pair as shown below.

“connection_id”: the connection id used by the holder agent that can communicate with the holder agent.

a list of “name” and “value” pairs inside the “attributes” block which is inside the “credential_preview” block: the value of each “name” MUST match each of the attribute type defined in the credential schema; the value of each “value” should be a proper value we expect for each “name”.

“cred_def_id”: the credential definition id, which can be obtained when a new credential definition has been created.

“issuer_did”: issuer’s public did, which can be obtained when creating a public did.

“schema_id”: a credential schema id, which can be obtained when creating a new credential schema.

“schema_issuer_did”: issuer’s public did if the same issuer creates this did

“schema_name”: a credential schema name, which is defined when creating a new credential schema.

“schema_version”: a credential schema version, which is defined when creating a new credential schema.

Figure 7 shows how they look like in the example of this blog. Figure 8 shows a new issued credential is done. This can be verified by looking at the value of the “state” attribute that shows “offer-sent”. Figure 9 shows a credential preview generated from the issuer as a response to the requester’s credential proposal.

figure 7— example of how attributes look like
figure 8 — JSON response message shows an offer is sent from the issuer as a response to the requester’s credential proposal
figure 9 — JSON response shows what a credential the issuer will issue

Step 3: Requester sends a formal credential request

Requester can now call the GET API: /issue-credential-2.0/records which shows the state of a record is “offer-received” as shown in figure 10, and a credential preview as shown in figure 11.

figure 10 — offer received on the requester agent
figure 11 — credential preview on the requester agent

Note: please note down the value of the field “cred_ex_id” for requester as well as shown in figure 12.

figure 12 — cred_ex_id belongs to the requester

Assuming the requester is happy with the credential proposal response. It can then call a POST API named: /issue-credential/records/{cred_ex_id}/send-request on the issuer agent (see figure 13). Replace the {cred_ex_id} with the value as shown in figure 12. No JSON body is required for this API, which simplifies the request itself.

figure 13 — API call to send a formal credential request

Once the API call occurs, the JSON response message will show the state of the record has been updated to “request-sent” as shown in figure 14. If we try to hit the GET API: /issue-credential-2.0/records again now, we should also see the state is updated to “request-sent”.

figure 14 — the requester has sent a formal credential request

Step 4: Issuer sends a newly issued credential

Issuer can now call the GET API: /issue-credential-2.0/records, and find the state of the record has been updated to “request-received” as shown in figure 15, which indicates this is formal credential request from the requester.

figure 15 — record’s state indicates this is a formal credential request

Issuer can now call a POST API named: /issue-credential/records/{cred_ex_id}/issue to issue a new credential as shown in figure 16. Again, use the previous value of the field of “cred_ex_id” on the issuer side.

figure 16 — API to issue a new credential

The only JSON body needed is a field called “comment”.

“comment”: whatever information the issuer wants to give to the requester in relation to this newly issued credential.

An example is given in figure 17.

figure 17 — comment in the JSON body for the issuer to send a newly issued credential

In the JSON response message, we can see the value of the “state” field has been updated to “credential-issued” as shown in line 43 in figure 18.

figure 18 — JSON response shows a newly issued credential has been sent to the requester

Step 5: Requester stores the credential to its own wallet

If the requester now calls the GET API: /issue-credential-2.0/records, we can see the state of the record is “credential-received” as shown in figure 19.

figure 19 — records shown on the requester side shows a credential is received.

The tricky bit in ACA-Py here is that even though the record’s state shows a credential has been received, but there is no real credential in the requester’s wallet. We can prove this by calling the GET API: /credential to verify this fact as shown in figure 20.

figure 20 — no credential can be retrieved from the requester’s wallet

In order to view this credential, we have to call an extra POST API: /issue-credential/records/{cred_ex_id}/store as shown in figure 21. Again, replace the real value of the “cred_ex_id” for the requester, which should be noted down in the previous step.

figure 21 — API to store the credential to a wallet

After calling this API, the state of the record is now updated to “done” (see figure 22). This means the credential is now available in the requester’s wallet.

figure 22 — a credential is now available in the requester’s wallet

Now, if we call the GET API: /credential again, we can see the credential in the requesters wallet now (see figure 23). This also shows which credential schema and definition the credential is based on.

figure 23 — credential is retrievable in requester’s wallet

Conclusion

Hopefully, the process of requesting, issuing and retrieving a credential would work for you as well if you follow all the steps in this part. I’ve highlighted the tricky bit for how to retrieve a credential for the requester. Next part will show you how a verifier can verify the authenticity of a credential claim presented by the requester. I’ll see you there.

--

--

Dr. Yunxi Zhang

Dr. Zhang works as a Tech Arch at Accenture. His interests cover Enterprise System Architecture, DLT, Cloud Services and DevOps.