Credential Issuance
Credential Issuance Service provides applications with secure methods of issuing and claiming credentials. It implements the OID4VCI (OpenID for Verifiable Credential Issuance) protocol, which provides the mechanism for Issuers to issue Verifiable Credentials to Affinidi Vault users and obtain the credentials using the OAuth 2.0 authorisation flow.
The Credential Issuance Service follows a pre-defined Schema to issue Verifiable Credentials to users and cryptographically signs the credentials using wallets. The verifiers/requesters can later use the Issuer’s DID value to verify the credentials.
Benefits of Credential Issuance Service
Secured Issuance and Claim: The issuance and claim of Verifiable Credentials uses OpenID for Verifiable Credential Issuance (OIDVCI) standard, which is an OAuth 2.0-based mechanism to authorise access to the issued credentials benefiting from its well-established security, simplicity, and flexibility.
Issue VCs from Preferred Wallet: The Credential Issuance Service allows Issuers to select from the list of supported Wallets (DID Methods) to issue and sign the credential, enabling them to utilise the provided benefits of each wallet.
W3C-compliant Credential Issuance: The Credential Issuance Service issues credentials to users using the W3C Verifiable Credential standard and allows you to define the list of supported schemas for your issuance flow.
How Credential Issuance Works
When issuing a Verifiable Credential, three main flows happen within the whole process:
Issuance Configuration
First, the Issuer creates the issuance configuration required to issue Verifiable Credentials to the consumers. In this configuration, they select the wallet that will sign the credentials and list the supported schemas to create the user credential offer. Supported schemas can be multiple types with different data structures depending on the requirements.
sequenceDiagram actor Developer participant Affinidi Portal participant Credential Issuance Service Developer->>Affinidi Portal: Configure a Credential Issuance Config Affinidi Portal->>Credential Issuance Service: Create a Credential Issuance Configuration Note over Affinidi Portal, Credential Issuance Service: Credential Issuance Configuration allows only 1 configuration per Project Credential Issuance Service->>Credential Issuance Service: Create / Link a wallet for signing Credential Issuance Service->>Credential Issuance Service: Create an Issuance Configuration with details provided Credential Issuance Service->>Affinidi Portal: Return the created/linked wallet, including supported Schema Affinidi Portal->>Developer: Provide details of the Issuance Configuration to use for issuing credentials
To create an Issuance Configuration, follow these steps.
Credential Issuance Flow
In the Credential Issuance flow, Issuers implement the required business logic within their applications, which initiates the issuance of a credential offer that users can claim in their Affinidi Vault.
For example, on an Online Course website, you can issue a credential attesting that the student completes the course.
In this example, the website calls the Credential Issuance Service to create a Credential Offer containing the details about the course. The structure of the Credential Offer is based on one of the supported schemas configured in the Issuance Configuration. It returns the URI of the Credential Offer and Transaction Code that the website sends to the user to claim from the Affinidi Vault.
sequenceDiagram participant Website participant Credential Issuance Service actor User User-->>Website: Completes a task or course and request for certificate. Website->>Credential Issuance Service: Create a credential offer for the user Note over Website, Credential Issuance Service: Credential data includes the supported Schema, User's wallet DID, and credential details to issue Credential Issuance Service->>Credential Issuance Service: Validates the credential data based on Issuance Configuration Credential Issuance Service->>Credential Issuance Service: Signs the Credential with the configured wallet Credential Issuance Service->>Website: Returns the Transaction Code and Offer URI to claim the credential from the Affinidi Vault Website-->>User: Send the Credential Offer to the user with the Transaction Code to claim the credential in a form of a link or QR code
Note
By default, a Credential Offer is created with claim mode asTRX_CODE
, which generates a transaction code required to retrieve the credential details.Credential Offer Claim Flow
The Credential Offer is only valid for claims based on the Lifetime of the Credential Offer
configured in the Issuance Configuration. If the user fails to claim the credential by this time, the website should create new credential offer.
When the user clicks on the Credential Offer link, it redirects them to the Affinidi Vault’s claim credential page. The Affinidi Vault exchanges the pre-authorisation code
and transaction code
to get the access token
required to retrieve the credential details.
While retrieving the credential details, the Credential Issuance Service validates the proof of the credential to verify that the user claiming the credential matches the Holder’s DID set in the Credential Offer. It throws an error if the proof validation fails.
Once the user accepts the credential, it is securely stored in the Affinidi Vault, where it can be shared later when requested.
sequenceDiagram actor User participant Affinidi Vault participant Credential Issuance Service participant Website User->>Affinidi Vault: Enters the Transaction Code to view the Credential Offer Affinidi Vault->>Credential Issuance Service: Resolves Offer URI and get the Credential Offer with Access Token Note over Affinidi Vault, Credential Issuance Service: Affinidi Vault will exchange Trx Code and Pre-Auth Code <br /> for the Access Token to Get the Credential Credential Issuance Service->>Credential Issuance Service: Validate credential proof Credential Issuance Service->>Credential Issuance Service: Update Credential Offer as Claimed Credential Issuance Service->>Affinidi Vault: Return the Verifiable Credential Affinidi Vault->>User: Presented the Verifiable Credential User->>Affinidi Vault: Accepts the Verifiable Credential Affinidi Vault->>Affinidi Vault: Securely Stores the Verifiable Credential Website-->>Credential Issuance Service: Checks the status of the Offer Website-->>Website: Update the website based on the Offer status
Note
After Affinidi Vault successfully retrieves the details of the Credential Offer from the Credential Issuance Service, the Credential Offer is updated asclaimed
status. However, users can still reject the credential and not store it in their Affinidi Vault.Issuing a Verifiable Credentials
Enable your application to issue Verifiable Credentials to Affinidi Vault users.
Set up Issuance Configuration
To issue a Verifiable Credential, it is required to setup the Issuance Configuration on your project, where you select the issuing wallet and supported schema to create a credential offer that the application issue
You can easily do this using the Affinidi Portal:
Go to
Affinidi Portal and click on the Credential Issuance page.
Click on Create Configuration and set the following fields:
Issuing Wallet: Create a new wallet and provide the new wallet name or select an existing Wallet that will sign and issue the credentials to the user. Read more about Wallets here.
Lifetime of Credential Offer: Credential Offers have a limited lifetime to enhance security. Consumers must claim the offer within this timeframe.
Supported Schemas: List of allowed schemas for creating a credential offer. Issuance will validate the credential data based on the supported schema before creating the Credential Offer. Create the Schema through the Schema Builder.
- After setting the fields and providing the list of the supported schema, click Create.
![Create Credential Issuance](/images/docs/cis-create-page.png)
Note
Currently, the Credential Issuance Service only supports one Issuance Configuration per Project.Create a Credential Offer
After setting up the Issuance Configuration, use the Issuance Client of the Affinidi TDK to enable your application to create a Credential Offer to Affinidi Vault users.
In this example, we will create a Credential Offer for a course completion use case. Follow the sample code below to initiate a Credential Offer to the user.
Getting the Holder DID
To get the Holder DID (holderDid
) required to create a Credential Offer, your website can implement Affinidi Login to authenticate and extract the user DID from the ID Token provided. You can explore our Labs to learn how to integrate Affinidi Login.- Install the required libraries (in our example, we will use Credential Issuance Service).
npm install -S @affinidi-tdk/auth-provider @affinidi-tdk/credential-issuance-client
# NOTE: affinidi_tdk.* is not published to PyPi yet
pip3 install <PATH_TO_PYTHON_AUTH_PROVIDER_FILE> <PATH_TO_PYTHON_LOGIN_CONFIG_CLIENT_FILE>
- Import the libraries into the code. We are importing the Credential Issuance client (Credential Issuance Service) to create a Credential Offer and the Auth Provider to generate the Project Scoped Token for the Authorisation header.
import { IssuanceApi, Configuration as AuthConfiguration } from '@affinidi-tdk/credential-issuance-client'
import { AuthProvider } from '@affinidi-tdk/auth-provider'
import affinidi_tdk_auth_provider
import affinidi_tdk_credential_issuance_client
from affinidi_tdk_credential_issuance_client.models.start_issuance_input import StartIssuanceInput
from affinidi_tdk_credential_issuance_client.models.start_issuance_response import StartIssuanceResponse
from affinidi_tdk_credential_issuance_client.rest import ApiException
- Generate an Authorisation token to call the client using the Personal Access Token for the specific project.
// NOTE: set your variables for PAT
const privateKey = '<PRIVATE_KEY_STRING>'
const publicKey = '<PUBLIC_KEY_STRING>'
const passphrase = '<KEY_PAIR_PASSPHRASE>'
const keyId = '<KEY_ID>'
const tokenId = '<PAT_ID>'
const projectId = '<PROJECT_ID>'
const tokenEndpoint = 'https://apse1.auth.developer.affinidi.io/auth/oauth2/token'
const apiGatewayUrl = 'https://apse1.api.affinidi.io'
const authProvider = new AuthProvider({
privateKey,
publicKey,
passphrase,
keyId,
machineUserId,
projectId,
tokenEndpoint,
apiGatewayUrl
})
const authConfiguration = new AuthConfiguration({
apiKey: authProvider.fetchProjectScopedToken.bind(authProvider)
})
stats = {
'privateKey': '<PRIVATE_KEY_STRING>',
'publicKey': '<PUBLIC_KEY_STRING>',
'passphrase': '<KEY_PAIR_PASSPHRASE>',
'keyId': '<KEY_ID>',
'machineUserId': '<PAT_ID>',
'projectId': '<PROJECT_ID>',
'tokenEndpoint': 'https://apse1.auth.developer.affinidi.io/auth/oauth2/token',
'apiGatewayUrl': 'https://apse1.api.affinidi.io'
}
authProvider = affinidi_tdk_auth_provider.AuthProvider(stats)
projectScopedToken = authProvider.fetch_project_scoped_token()
configuration = affinidi_tdk_credential_issuance_client.Configuration(
host = "http://localhost"
)
# Configure API key authorization: ProjectTokenAuth
configuration.api_key['ProjectTokenAuth'] = projectScopedToken
- Initiate the Issuance module with the authorisation header and call the client method with the credential data.
const api = new IssuanceApi(authConfiguration)
const projectId : string = 'Project_ID'
const request: StartIssuanceInput = {
'data': [{
'credentialTypeId': 'SchemaOne',
'credentialData': {
'first_name': 'FirstName',
'last_name': 'LastName',
'course': 'Fundamentals of Decentralised Identity',
'completion_date': '2024-01-01'
}
}],
'holderDid': 'did:key:holder-did-value',
'issuanceId': 'Issuance_ID'
}
const { data } = await api.startIssuance(projectId, request)
with affinidi_tdk_credential_issuance_client.ApiClient(configuration) as api_client:
api_instance = affinidi_tdk_credential_issuance_client.IssuanceApi(api_client)
projectId = 'Project_ID'
request_json = "[{
'data': {
'credentialTypeId': 'SchemaOne',
'credentialData': {
'first_name': 'FirstName',
'last_name': 'LastName',
'course': 'Fundamentals of Decentralised Identity',
'completion_date': '2024-01-01'
}
}],
'holderDid': 'did:key:holder-did-value',
'issuanceId': 'Issuance_ID'
}"
start_issuance_input = affinidi_tdk_iam_client.StartIssuanceInput.from_json(request_json)
api_response = api_instance.start_issuance(projectId, start_issuance_input=start_issuance_input)
The Issuance Service will return the Credential Offer URI and the Transaction Code to obtain the credential details. Your application should send this information securely to the intended user to claim the Credential Offer within the configured duration in the Issuance Configuration.
{
"credentialOfferUri": "https://<PROJECT_ID>.apse1.issuance.affinidi.io/offer/3da42adc-5412-413b-986c-99c43cb87eba",
"txCode": "123456",
"issuanceId": "3da42adc-5412-413b-986c-99c43cb87eba"
"expiresIn": 3600
}
Claiming the Credential Offer
To allow the recipient of the Credential Offer to claim the credential and store it on their Affinidi Vault, developers can send the claim link via email or QR code, for example. The claim link will be in the following format with the URL encoded <CREDENTIAL_OFFER_URI>
value:
https://vault.affinidi.com/claim?credential_offer_uri=<CREDENTIAL_OFFER_URI>
If the Credential Offer was created with the Transaction Code (txCode
), the developer must also send the Transaction Code for the user to claim the credentials.
Glad to hear it! Please tell us how we can improve more.
Sorry to hear that. Please tell us how we can improve.
Thank you for sharing your feedback so we can improve your experience.