- Introduction
- Reference system
- Work flow
- Create DID in a wallet
- Schema definition by a legal entity
- Establish connection between Issuer and Holder
- Credenial issuance by the issuer (Test Center)
- Stores credential into a personal wallet (Data4Life)
- Proof presentation by Holder (Data4Life) to Verifier (Travel Company)
- References
This describes the API call flows during a verified data exchange process using hyperledger Indy as the distributed ledger registry and hyperldge aries agent for client application.
The indy network is up and running at https://indy.igrant.io/. The aries agents are connected to this network and configured locally as described here. Executing the sequence of operations described creates the reference system described below.
In our reference implementation, we have the individual (Alice) holding her health data in her wallet app (Data4Life) issued by a Health Test Center. This health data could be used by Alice to prove her health status to a travel company. The legal entity ensures that the test center follows the schema and governance.
Once the reference system is up and running you can start 3 terminals and monitor their logs by executing the docker container logs given below:
Agent | Swagger API endpoint admin UI |
---|---|
Test Center | docker exec -it test-center.webhook tail -f demo.log |
Alice (Data4Life User) | docker exec -it data4life-user.webhook tail -f demo.log |
Travel Company | docker exec -it travel-company.webhook tail -f demo.log |
In your browser you can start three tabs to execute the APIs using swagger.
Agent | Swagger API endpoint admin UI |
---|---|
Test Center | test-center.swagger.localhost |
Alice (Data4Life User) | data4life-user.swagger.localhost |
Travel Company | travel-company.swagger.localhost |
Alice is a travel vloger, Her next destination is dubai but, due to covid pandemic, she has to prove to a travel agent, that her result is negative. So that she will be allowed to travel.
Alice listed out the things she has to do:
-
Visit a covid test center
Note: Test center should follow a schema defined by a legal entity to issue the certificate. Refer schema definiton by legal entity- Test center and alice creates a connection to exchange information. Refer Establish connection between Issuer and Holder
- The Test center will test alice's samples and issues a certificate. Refer Credenial issuance by the issuer
-
Store the issued credentials to her wallet. Refer Stores credential into a personal wallet
-
Present proof to travel agent. Refer Proof presentation by Holder
Alice will be allowed to travel affter completing these steps.
The work flow can be performed either manually or automatically. By default it will be automatic. To make it manual replace the code of startup.sh with code of startup_temp.sh
The steps below to create DID in a wallet is a pre-requesite for any agent before acquiring agent roles.
-
Create a local DID for the agent using
POST /wallet/did/create
This generates the DID and verification key -
For organisations, After creating local DID, you need to register it with ledger at indy.igrant.io as shown below
After registering with the Indy ledger call
POST /wallet/did/public
To make it easier, we have used the Test Center Agent to register the schema. Ideally this is defined by a legal entity or a standardisation body.
You can execute the schema definiton API to register the schema in the ledger.
To define schema first you have to create a public DID. This is done following the previous step: Create DID in a wallet
Sends a schema to the ledger with the API POST: /schemas
with the json body as given:
{
"schema_version": "1.0",
"schema_name": "Covid-19 Test Results",
"attributes": [
"testResult",
"testDate"
]
}
Try out on your local machine at: http://test-center.swagger.localhost/api/doc#/schema/post_schemas
Here, the Test Center and Data4Life-User agents establishes connection with each other. Following are the API call sequence:
-
Create a new invitation (by Test Center)
Test Center Agent:
POST /connections/create-invitation
This generates the
connection_id
andinvitation
.{ "connection_id": "e18c5108-4040-4a1e-b994-e80eaab5e3d2", "invitation": { "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation", "@id": "903fc685-0463-4f92-93ff-43dbdbfb1297", "serviceEndpoint": "http://test-center.localhost", "recipientKeys": [ "7eCdJgj5r5ZjGYqVJYGTjdjFqxNnP3oWxYseagPoB1gg" ], "label": "Test-Center" }, "invitation_url": "http://test-center.localhost?c_i=eyJAdHlwZSI6ICJkaWQ6c292OkJ6Q2JzTlloTXJqSGlxWkRUVUFTSGc7c3BlYy9jb25uZWN0aW9ucy8xLjAvaW52aXRhdGlvbiIsICJAaWQiOiAiOTAzZmM2ODUtMDQ2My00ZjkyLTkzZmYtNDNkYmRiZmIxMjk3IiwgInNlcnZpY2VFbmRwb2ludCI6ICJodHRwOi8vYWdlbnQzLmxvY2FsaG9zdCIsICJyZWNpcGllbnRLZXlzIjogWyI3ZUNkSmdqNXI1WmpHWXFWSllHVGpkakZxeE5uUDNvV3hZc2VhZ1BvQjFnZyJdLCAibGFiZWwiOiAiVHJhdmVsLUNvbXBhbnkifQ==" }
Try out on your local machine at: http://test-center.swagger.localhost/api/doc#/connection/post_connections_create_invitation
-
Receive a new connection invitation by Data4Life-User (Alice) with the connection_id.
Alice Agent:
POST /connections/receive-invitation
with the invitation invitation json (shown below) generated in step 1 as input.`{ "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation", "@id": "903fc685-0463-4f92-93ff-43dbdbfb1297", "serviceEndpoint": "http://test-center.localhost", "recipientKeys": [ "7eCdJgj5r5ZjGYqVJYGTjdjFqxNnP3oWxYseagPoB1gg" ], "label": "Test-Center" }`
-
Accept a received connection invitation by Data4Life-user (Alice)
Alice Agent:
POST /connections/{conn_id}/accept-invitation
passing theconnection_id
as input.
- Repeat steps 1 - 3 of automated workflow.
- Now the connection will be in request state, Issuer (Test Center) has to accept the request
Test Center Agent:POST /connections/{conn_id}/accept-request
Now the state changes to response - To make the connection active we have to call the trust ping endpoint either from issuer (Test Center) or from holder (Alice).
Test Center/Alice Agent:POST /connections/{conn_id}/send-ping
Check both Test Center Agent and Alice Agent by GET /connections
and both are in Active
status
After the secured connection is established between the two agents, the Test Center first establishes the connection with Alice. After that the Test Center issues credential to them with their own personal data. Alice then is able to see the credential in her Data4Life wallet.
Here, a credential is issued by the Test Center based on a standard scehma earlier defined by the legal entity.
-
Create a local DID for the test center and make it public by publishing it to the ledger. Follow the previous instruction: Create DID in a wallet.
-
Repeat step 1 to create DID for the Data4Life-User, but DO NOT publish this to ledger as it shall remain private.
-
Now, based on the schema, Test Center creates a credential definition to the ledger.
An example scheme ID and name is as given. Please use the ones that were created during schema defintion or pick one from indy ledger.
Schema ID: PWr9PACurgoMwowC5Bx8RD:2:Covid-19 Test Results:1.0 Schema Name: Covid-19 Test Results:1.0
POST method /credential-definitions
sends a credential definition to the ledgerNOTE: Make sure revocation is false in the paylod example as given below:
{ "revocation_registry_size": 0, "support_revocation": false, "schema_id": "PWr9PACurgoMwowC5Bx8RD:2:Covid-19 Test Results:1.0", "tag": "default" }`
-
Test Center now issues the credenital to the holder Alice (Data4Life-user)
Test Center Agent:
POST /issue-credential/send
with auto_remove set to FALSE
{ "schema_name": "Covid-19 Test Results", "schema_version": "1.0", "cred_def_id": "PWr9PACurgoMwowC5Bx8RD:3:CL:19:default", "auto_remove": false, "comment": "string", "connection_id": "a8ea680f-0704-4327-99b8-02e5e3d03ea4", "trace": false, "schema_issuer_did": "PWr9PACurgoMwowC5Bx8RD", "schema_id": "PWr9PACurgoMwowC5Bx8RD:2:Covid-19 Test Results:1.0", "issuer_did": "PWr9PACurgoMwowC5Bx8RD", "credential_proposal": { "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview", "attributes": [ { "name": "testDate", "mime-type": "text/plain", "value": "22-Aug-2020" }, { "name": "testResult", "mime-type": "text/plain", "value": "negative" } ] } }
-
Issuer (Test Center) sends a offer with the result of the test.
Test Center Agent:POST/issue-credential/send-offer
Note: In request body auto issue and auto remove should be false
{ "cred_def_id": "WgWxqztrNooG92RXvxSTWv:3:CL:20:tag", "credential_preview": { "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview", "attributes": [ { "name": "testDate", "mime-type": "text/plain", "value": "22-Aug-2020" }, { "name": "testResult", "mime-type": "text/plain", "value": "negative" } ] }, "connection_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "auto_issue": false, "comment": "string", "trace": false, "auto_remove": false }
Now the state will be offer_sent for Issuer (Test Center)
Note:
GET /issue-credential/records
to view the state -
Alice will call
GET /issue-credential/records
The state will be offer_received and from this response copy the credential exchange id. -
Alice will send request to issue the credential using credential exchange id.
Alice Agent:POST /issue-credential/records/{cred_ex_id}/send-request
Now the state will be request_sent for Alice -
Issuer (Test Center) will call
GET/issue-credential/records
The state will be request_received and from this response copy the credential exchange id. -
Issuer (Test Center) issues the certificate using credential exchange id
Test Center Agent: POST /issue-credential/records/{cred_ex_id}/issue
Now, the credential will be issued to Alice and state will change to credential_issued
In the case of automated flow, the credential is automatically stored into the wallet. In the case of manual flow, this need to be done explicitly.
For manual flow, Alice, the Data4Life-User, now stores the received credentials
Alice Agent: POST /issue-credential/records/{cred_ex_id}/store
Data4Life user can fetch the credentials from the wallet by GET /credentials
Before any communication happens between Alice (Data4Life-User) and the verifier, a secured connection is established between two agents. After that Travel Company issues a proof request to Alice, showing what type of proof is needed to qualify in order for Alice to travel using the Covid-19 test result. Alice will build the proof based on the credential in her Data4Life wallet. Alice then sends the proof to the travel company which will observe the result.
-
Establish connection
Travel Company Agent:
POST /connections/create-invitation
, from the response get the invitation object (from{ to }
) as shown earlier during the connection between Test Center and Alice.Alice Agent:
POST /connections/receive-invitation
with the invitation object -
Accept a stored connection invitation by Alice (Data4Life user)
Alice Agent:
POST /connections/{conn_id}/accept-invitation
passing theconnection_id
as input.
Check both Travel Company Agent and Alice Agent by GET /connections
and both are in Active
status
After the secured connection is established between the two agents, the Travel Center request a proof from Alice as per the credenital defintion. The following steps cover that flow.
-
In this demo, the Proof request details the Test Center is asking for is
testResult testDate
all items follows the Credential Definition specified by the ID
Travel Center Agent:
POST /present-proof/send-request
is called with the following payload (example){ "connection_id": "a8ea680f-0704-4327-99b8-02e5e3d03ea4", "comment": "Ready to travel", "proof_request": { "name": "Proof of COVID19 Negative", "version": "1.0", "requested_attributes": { "0_testresult_uuid": { "name": "testResult", "restrictions": [ { "cred_def_id": "PWr9PACurgoMwowC5Bx8RD:3:CL:19:default" } ] }, "0_testdate_uuid": { "name": "testDate", "restrictions": [ { "cred_def_id": "PWr9PACurgoMwowC5Bx8RD:3:CL:19:default" } ] } }, "requested_predicates": {} } }
Using the requested_predicates, you can do some assertions, example, the testDate shall be less than 2 days from today.
In the webhook interceptor, you can view the sequence of events happening:
- receiving the proof request
- checking credentials
- generating proof
- sending proof to Travel Company
-
From Travel Company, we can use
GET /present-proof/records
to see the proof sent by Alice. Thepresentation_exchange_id
is the identifier of the presentation proof and state will tell you the current status of the presented proof.
-
Repeat steps 1 - 2 of automated flow
-
Now the connection will be in request state, Verifier (Travel company) has to accept the request.
Travel Company Agent:POST /connections/{conn_id}/accept-request
Now the state changes to response. -
To make the connection active we have to call the trust ping endpoint either from Verifier (Travel company) or from holder (Alice).
Travel Company/Alice Agent:POST /connections/{conn_id}/send-ping
-
Perform step 3 of automated flow.
-
Holder (Alice) has to get the presentation exchange id
Alice Agent:GET /present-proof/records
-
Holder (Alice) will send the presentation
Alice Agent:POST /present-proof/records/{pres_ex_id}/send-presentation
is called with the following payload (example){ "requested_predicates": { }, "trace": false, "self_attested_attributes": { }, "requested_attributes": { "0_testresult_uuid": { "cred_id": "b5df5eac-047f-4ad0-98cc-7e6138a2f339", "revealed": true }, "0_testdate_uuid": { "cred_id": "b5df5eac-047f-4ad0-98cc-7e6138a2f339", "revealed": true } } }
Note: requested_attribute fields keys should be same as in the body of POST /present-proof/send-request
7. Finally Travel Company use POST /present-proof/{pres-ex-id}/verify-presentation
to see Alice’s proof presentation.