Issue a credential
The issuance workflow consists in three actions:
Create a credential
Issue the credential
Manage the credential
Here you will learn what is required for each step and how to complete them.
Create a credential
A credential consists of a few components:
- Credential schema
- Claims being asserted
- Issuer identifier
- Choice of exchange protocol
- Optional:
- Key to use for assertion
- Redirect URI
Credential schema
A credential schema defines the type of credential you are issuing and includes components such as:
- How the credential data will be formatted and secured.
- The method to be used for future suspension and revocation, if any.
- The kind of claims that will be asserted during issuance, in the form
of keys such as
Name
orBirthdate
and datatypes for validating the claims made during issuance. - Design and layout properties of the credential, so wallets know how to render the credential visually for the holder.
- Issuer requests about the properties of the wallet, such as whether the wallet should use software- or hardware-based keys for signing the credential on issuance.
The schema is crucial for defining and distributing the expected structure of credentials, allowing wallets and verifiers to parse, interpret and handle credentials appropriately.
When creating a credential you choose a schema that has already been created, defining the type of credential you plan on issuing. For guidance on creating a credential schema, see the related guide: Credential schemas.
Claims assertion
Issuing a credential is asserting claims about a subject. During the
credential creation process you take the claims keys from the credential
schema and fill in real values. These values can be alphanumeric strings,
numbers, booleans, dates, or files such as photographs. The claim key is
a human-readable attribute name that defines the nature of the claim;
common keys are things like Name
, Address
, Birthdate
, Photo
,
Employee number
and other similar keys.
In addition to defining the attribute keys of a credential, the schema defines a few components that shape how you assert claims during credential creation:
- Whether a claim key requires a value or if it can be left empty during issuance.
- What kind of data is expected for a value.
- The data structure of claims when the datatype is
OBJECT
or when the claim is an array, or list.
If a claim is required by the schema but no value is entered, or if a claim expects a date but a file is entered, or if the data structure passed for the claims does not match up with what is defined in the schema, an error is returned and the credential is not created.
Related guide: Datatypes
Claim values in the API
Use the claimValues[]
object to make claims during credential creation.
For each claim being made, three things are required:
{
"claimValues": [
{
"claimId": "31e4e82e-1663-4775-ad6a-bf828037eace", // UUID of the claim from the credential schema
"path": "Family plan members/0/Full name", // path, described below
"value": "Jim Smith" // value being asserted by the issuer
}
]
}
path
is used to point to the particular claim key within the structure of the
credential schema. This field accepts a JSON Pointer with the following format:
root/nested_array/0
For single attribute claims that are neither an obect nor an array, the path is the attribute key (that is, the root object):
{
"claimId": "3246dbce-f04a-40e8-a3c4-7784ce420afb",
"path": "First name",
"value": "Alice"
},
For arrays, the root is followed by the index (note that the claimId
is the same):
{
"claimId": "469b303a-8bf6-4207-acdb-6be79ab5c751",
"path": "Attribute key/0", // first item in the array
"value": "First array item value"
},
{
"claimId": "469b303a-8bf6-4207-acdb-6be79ab5c751",
"path": "Attribute key/1", // second item in the array
"value": "Second array item value"
},
For objects, the root is the name of the object followed by the relevant attribute key:
{
"claimId": "ccba3d15-59d5-4d7e-a327-bfe282c38cd4",
"path": "Object/Attribute key 1",
"value": "Attribute value 1"
},
{
"claimId": "02a1a327-3e75-4f06-8849-126378cf8f2a",
"path": "Object/Attribute key 2",
"value": "Attribute value 2"
}
If this last claim were an array, the index would be added to the path:
{
"claimId": "02a1a327-3e75-4f06-8849-126378cf8f2a",
"path": "Object/Attribute key 2/0",
"value": "Attribute value 2"
}
Issuer identifier
Issued credentials contain metadata about who issued them. The system requires you to specify a Decentralized Identifier (DID) which will go into the credential as a unique identifier for you as an issuer.
Important considerations for choosing a DID:
- Some DID methods in the system are format-specific or act as proxies.
For example,
did:mdl
is a proxy DID method that does not represent a real DID method according to the W3C standard but enables Document Signer Certificates to work within standard credential flows. When issuing an ISO mdoc, you must use did:mdl as the identifier. Check thecapabilities.issuanceDidMethods
of your chosen credential format to see which DID methods are supported. - Some credential formats have limitations with the type of key algorithm
that can be used to sign the credential. You must choose a DID
which has as its assertion method a key which is compatible with the
credential format. When you get the configuration through the API, check
the
capabilities.signingKeyAlgorithms
of the credential format specified in the schema for a list of all key algorithms that can be used to sign during issuance. - With the Procivis Trust Registry, trust management runs through DIDs. If you want the wallet holder and the verifier to know that you are a trusted issuer, be sure to use a DID that is registered as a trust entity on the system's trust anchor.
Related guides: Capabilities and Procivis Trust Registry
Exchange protocol
An exchange protocol defines how the credential is issued to the wallet holder. It's a language that both the issuer and the wallet speak so that credentials can be successfully bundled up and transmitted from the issuer to the holder's wallet.
Important considerations for choosing an exchange protocol:
- The wallet you are issuing to must support the chosen protocol. When you later issue the credential, the system generates a URL that is specific to the exchange protocol. The wallet must be able to parse this URL to retrieve and accept the offered credential.
- Some exchange protocols are only used for verifying credentials.
When retrieving the configuration through the API, check the
capabilities.issuanceExchangeProtocols
of the credential format specified in the schema for a list of all exchange protocols that can be used to issue credentials of that format. - Some DID methods may not be compatible with some exchange protocols. When
you get the configuration through the API, check the
capabilities.issuanceDidMethods
for a list of DID methods that are compatible with the given exchange protocol. - Some operations for exchange protocols may be disabled in the configuration.
When you get the configuration through the API, check the
capabilities.operations
for a list of operations enabled for the given exchange protocol.
Related guides: Capabilities
Optional parameters
- Some DIDs use multiple keys for their verification methods. If the DID
chosen for issuance has multiple keys specified for its assertion method,
the credential creation process is an opportunity to specify which key
to use for signing this particular credential. If a key is not specified
with the
issuerKey
parameter, the system uses the first key listed in the DID's assertion method. - During credential creation you can specify a redirect URI. Use this
for a standard URL or for a deep link. When the wallet holder accepts
the credential issuance, they are taken to the resource specified at
redirectUri
.
Related guide: Keys object
Putting it together in an API call
Here's an example curl
call, without headers, to create a credential:
-d '{
"claimValues": [
{
"claimId": "38569fa1-10ba-4ad6-abb5-0c7dfa09b6a3",
"path": "Name",
"value": "Jane A. Smith"
},
{
"claimId": "c62e6f62-e4f5-4416-a0be-f371aa1e7e86",
"path": "Address/Street",
"value": "123 Maple St."
},
{
"claimId": "058597d2-5048-4b51-b434-ae2b72086f4b",
"path": "Address/City",
"value": "Springfield"
},
{
"claimId": "3899e362-b897-4d4a-8d11-70b1875fa532",
"path": "Address/Postal code",
"value": "62701"
},
{
"claimId": "18f1bd79-d7f3-4414-bc29-95f399cbb1cc",
"path": "Date of birth",
"value": "1985-01-14T23:00:00.000Z"
},
{
"claimId": "abd3cb68-3dca-43ce-a94c-dd69853cd45d",
"path": "Email",
"value": "jsmith85@example.com"
}
],
"credentialSchemaId": "ad0e33be-09ca-4b84-8bb6-be761cbf2a7d",
"exchange": "OPENID4VC",
"issuerDid": "a635a9e2-e6f0-4ef3-9800-6e9c38e5a258",
"redirectUri": "https://www.example.com/accepted"
}'
Here we have specified:
- What type of credential we're issuing via the UUID of the credential schema.
- Which DID we're using as the identifier via the UUID of the issuer DID.
- Which exchange protocol we will use to issue to the wallet.
- A redirect URI as a resource for the wallet holder to visit after acceptance.
- The set of claims we are making as an issuer.
Issue a credential
Creating a credential creates the data structure in the system but it doesn't, by itself, transmit it in any way to the appropriate wallet holder.
To issue the credential, pass the credential's UUID to the issue endpoint,
/api/credential/v1/:id/share
. This action generates a URL that results
from a combination of the system configurations and the exchange protocol
chosen for issuance. The generated URL is typically encoded in the frontend
as a QR code. The holder then scans the QR code, the wallet parses the code
according to the exchange protocol, and then fetches and presents the
offered credential to the wallet holder for review.
Manage a credential after issuance
If the wallet holder accepts the offered credential, management of the credential is done by maintaining the validity of the credential through the use of suspension and revocation, assuming the schema allows for suspension and revocation.
Related guide: Manage credential status