Issue Credentials

This section demonstrates how issuer1 issues a credential to user1.

First, there is some issuer initialization which must be performed.

Issuer initialization

There are three steps required in order to initialize an issuer.

  1. Onboard the issuer as an endorser (formerly known as a trust anchor)

    Onboarding an issuer as an endorser is required in order to grant permission to the issuer to write to the ledger. Both creating a credential schema and credential definition as described below require writing to the ledger.

    The following command on-boards issuer1 as an endorser:

    curl -u $ISSUER1 -X PATCH -d '{"role":{"name":"ENDORSER"}}' $URL/api/v1/agents/$ISSUER1_ID -H 'Content-Type: application/json'

  2. Create a credential schema or get the DID of an existing credential schema

    A credential schema consists of a list of attribute names. It is written to the ledger and may be shared by multiple issuers.

    For example, suppose a credential schema which is used to issue job employment credentials has the following attribute names: name, employeeId, department, and dateOfHire. This credential schema could be used by multiple corporate issuers to issue job employment credentials to their employees.

    In this tutorial, issuer1 creates its own credential schema as follows: curl -u $ISSUER1 -X POST -d '{"name":"cred_schema1", "version": "1.0", "attrs": ["attr1", "attr2", "attr3"]}' $URL/api/v1/credential_schemas -H 'Content-Type: application/json' The names of the attributes in this schema are simply attr1, attr2, and attr3. The 'id' value in the response is referred to as the <schema_id> in the next step.

  3. Create a credential definition

    A credential definition is used by an issuer to issue credentials. It uniquely identifies both the agent which issues the credential and also the attributes which are in the credential. In other words, the credential schema is a template for issuing credentials whereas a credential definition is an instance of that template which is used by a single agent.

    Issuer1 creates a credential definition associated with the credential schema, where <schema_id> is the 'id' value from the response received in the previous step. curl -u $ISSUER1 -X POST -d '{"schema_id":"<schema_id>"}' $URL/api/v1/credential_definitions -H 'Content-Type: application/json'

Now that issuer initialization is complete, let's have issuer1 issue a credential to user1.

There are two types or issuance flows supported: issuer-initiated and user-initiated.

Issuer-initiated issuance

Issuer1 sends a credential offer to user1 by specifying the credential schema and version as follows:

curl -u $ISSUER1 -X POST -d '{"to": {"name": "user1"}, "schema_name": "cred_schema1", "schema_version": "1.0", "attributes": {"attr1": "attr1Val", "attr2": "attr2Val", "attr3": "10"}}' $URL/api/v1/credentials -H 'Content-Type: application/json'

Similarly, issuer1 can send a credential offer to user1 by specifying the credential definition ID as follows:

curl -u $ISSUER1 -X POST -d '{"to": {"name": "user1"}, "credential_definition_id": "<cred_def_id>", "attributes": {"attr1": "attr1Val", "attr2": "attr2Val", "attr3": 10}}' $URL/api/v1/credentials -H 'Content-Type: application/json'

Addressability

The "to" value of the body of the request identifies the target agent to which the credential offer is being sent. In the examples above, the "name" of the target agent is specified for readability. However, you may have connections to multiple agents with the same name, the name may change, or you may not even have a connection to the target agent all all. Therefore, multiple methods for addressing the target agent are supported as follows:

  1. By name

    You may specify the name of the target agent as follows: {"to":{"name":"<agent-name>"}}. This is a user-friendly method which is convenient for prototyping; however, since names are not guaranteed to be unique and the name may change, you should use another method for production.

  2. By connection ID

    You may specify the ID of a connection which you have with a remote agent as follows: {"to":{"id":"<connection-id>"}}. If you have a connection with the target agent and you know the ID of the connection, this is the recommended method. Keep in mind that if a connection is deleted and recreated to the same agent, it will have a different connection ID.

  3. By DID

    You may specify the DID of a remote agent as follows: {"to":{"did":"<DID>"}}. This also requires that you have a pre-existing connection with the target agent. The DID may be the value of the remote.public.did, remote.pairwise.did, or local.pairwise.did fields of the connection. If you have a connection with the target agent and you know the public DID of the target agent, this is the recommended method. This should often be the case when the target agent is associated with an issuer or verifier.

  4. By Invitation

    You may specify an invitation URL as follows: {"to":{"invitation":{"url": "<invitation-URL>"}}. This initiates a connection-less interaction and requires that you have an invitation URL from the target agent. The invitation URL can be either the url or short_url field from an invitation.

  5. Manual

    This is another method of initiating a connection-less interaction. In the manual method, you omit the "to" section altogether which means that you are taking responsibility for manually delivering the message to the remote agent. The Aries-compliant message which you must manually deliver is returned in the aries_message field of the response body. The way in which you manually deliver an Aries message to an agent depends on the type of the agent. To deliver an Aries message to an IBM Verify Credentials agent, use the POST /api/v1/aries_message API.


Now that issuer1 has sent the credential offer to user1, user1 views all credential offers as follows:

curl -u $USER1 $URL/api/v1/credentials?state=inbound_offer

This lists all credentials whose state if inbound_offer, where each credential has a unique id field value referred to as <id> below.

Or you can view a specific credential offer as follows, where <id> is the id field of the credential.

curl -u $USER1 $URL/api/v1/credentials/<id>

In either case, user1 views the offer.attributes section to see if it agrees with the attribute values being offered.

Assuming that user1 agrees with the attribute values, user1 accepts the credential offer as follows. Note that you must replace <id> with the value from the id field.

curl -u $USER1 -X PATCH -d '{"state":"accepted"}' $URL/api/v1/credentials/<id> -H 'Content-Type: application/json'

This results in a credential state of 'stored' for user1.

And it also results in a credential state of issued for issuer1 which can be viewed as follows:

curl -u $ISSUER1 $URL/api/v1/credentials/<id>

If user1 did not agree with the attribute values or just did not want to accept the credential offer for some other reason, there are two options:

  1. Reject the credential offer

    The following retains the credential object but changes its state to "rejected" for both user1 and issuer1: curl -u $USER1 -X PATCH -d '{"state":"rejected"}' $URL/api/v1/credentials/<id> -H 'Content-Type: application/json'

  2. Delete the credential offer

    The following deletes the credential object for user1 and changes the state of the credential object to "deleted" for issuer1: curl -u $USER1 -X DELETE $URL/api/v1/credentials/<id>

User-initiated issuance

The user-initiated issuance flow is similar to the issuer-initiated issuance flow except that it begins with an additional step: the user sends a credential request to the issuer, asking the issuer to create a credential offer.

User1 sends a credential request to issuer1

curl -u $USER1 -X POST -d '{"state": "outbound_request", "to": {"name": "issuer1"}, "schema_name": "cred_schema1", "schema_version": "1.0"}' $URL/api/v1/credentials -H 'Content-Type: application/json'

Issuer1 views all inbound credential requests and finds the one from user1, taking note of its id.

curl -u $ISSUER1 $URL/api/v1/credentials?state=inbound_request

Issuer1 issues a credential offer to user1 based on its request, where <id> is the id value from the previous step.

curl -u $ISSUER1 -X PATCH -d '{"state": "outbound_offer", "attributes": {"attr1": "attr1Val", "attr2": "attr2Val", "attr3": "10"}}' $URL/api/v1/credentials/<id> -H 'Content-Type: application/json'

From this point forward, the user-initiated issuance flow is identical to that of the issuer-initiated issuance flow.

User1 views all credential offers as follows:

curl -u $USER1 $URL/api/v1/credentials?state=inbound_offer

Or views this specific credential offer as follows:

curl -u $USER1 $URL/api/v1/credentials/<id>

In either case, user1 views the offer.attributes section to see the attribute values being offered.

User1 accepts the credential offer. Note that this results in a credential state of 'stored' for user1.

curl -u $USER1 -X PATCH -d '{"state":"accepted"}' $URL/api/v1/credentials/<id> -H 'Content-Type: application/json'

And it results in a credential state of issued for issuer1 which can be viewed as follows:

curl -u $ISSUER1 $URL/api/v1/credentials/<id>

Listing credential schemas and credential definitions

There's several ways we can list credential schemas and definitions. Let's start with viewing all definitions and schemas within an agency.

We can use the all query parameter to accomplish this.

curl -u $USER1 $URL/api/v1/credential_schemas?all
curl -u $USER1 $URL/api/v1/credential_definitions?all

Alternatively, in the case that you'd like to view schemas or definitions from only a specific issuer you can do that as well.

We can use several fields as query parameters to accomplish this. Most often, owner_did, name or id would be used. Where owner_did is the public DID of the credential definition or schema owner and where name and id are the name and id of the credential schema/definition respectively.

curl -u $USER1 $URL/api/v1/credential_schemas?owner_did=<public_did>
curl -u $USER1 $URL/api/v1/credential_definitions?name=<credential_def_name>

Listing credentials

The credentials held by user1 can be listed as follows:

curl -u $USER1 $URL/api/v1/credentials

And the credentials issued by issuer1 can be listed as follows:

curl -u $ISSUER1 $URL/api/v1/credentials

Deleting credentials

At this point in the tutorial, you should not delete any credentials; however, for your reference, it is easy to do.

You could delete a credential for issuer1 as follows:

curl -u $ISSUER1 -X DELETE $URL/api/v1/credentials/<id>

Or similarly, you could delete a credential for user1 as follows:

curl -u $USER1 -X DELETE $URL/api/v1/credentials/<id>

But for now, let's use the issued credentials to perform verification.