Eventi App will issue tickets as digitally verifiable credentials for their consumers who purchased event tickets to enable digital trust.
Credential Issuance Service provides applications with secure methods of issuing and claiming credentials. It implements the OpenID for Verifiable Credential Issuance - OID4VCI 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.
More Details on Affinidi Credential Issuance Service is available on Affinidi Documentation
We will use the Eventi
app that we generated in Module 1 and enable Affinidi Credentials Issuance Service to issue Event Tickets as digital verifiable credentials. We will dive into the Credentials Issuance feature to issue tamper-evident digital credentials, enabling trust in digital interactions through the flow of portable trusted data.
S.No | Content | Description |
---|---|---|
1. | Install Affinidi Trust Development Kit (TDK) | Import the Auth provider and Issuance Client packages to easily manage credential issuance |
2. | Setup Credential Issuance Configuration | Select the issuing wallet and supported schemas for issuing ticket as Verifiable credentials |
3. | Setup application frontend integration | Add IssueTicketVC() function inside checkout page for Verifiable Credential issuance |
4. | Bind the event handlers | Link the user actions to issuance flow |
5. | Setup application backend integration | Create API endpoint /api/issuance/start to issue Event ticket VC Offer using Affinidi TDK |
6. | Run & Test the application | Try the app with Affinidi Login & Affinidi Credentials Issuance Configuration |
Important
This Module is an extension of the same Eventi App that we worked on for Module 1.
Let's continue with the step-by-step guide to enable the Affinidi Credentials Issuance service in the sample App.
Install below Affinidi TDK packages as dependencies on this Eventi
application for Affinidi Credentials Issuance Client
and Affinidi TDK Auth provider
npm install @affinidi-tdk/auth-provider @affinidi-tdk/credential-issuance-client
Important
Personal Access Token (PAT) is like a machine user that acts on your behalf to the Affinidi services, which was automatically generated in previous module. If the automatic generation option was not selected in previous module, PAT can be generated manually using Affinidi CLI command.
-
To issue a Verifiable Credential, it is required to setup the Issuance Configuration on your project, where you select the issuing wallet and supported schemas to create a credential offer that the application can issue.
-
You can easily do this using the Affinidi Portal
-
Login on Affinidi Portal
-
Open the
Wallets
menu under theAffinidi Elements
section and click onCreate Wallet
with any name (e.g.MyWallet
) and DID method asdid:key
. This helps to setup Organisational identity for Eventi application that is used to sign the Event Ticket Verfiable Credentials later.For more information, refer to the Wallets documentation
-
Go to
Credential Issuance Service
under theAffinidi Elements
section. -
Click on
Create Configuration
and set the following fields:Name of configuration
asmyCISConfig
Issuing Wallet
: Select Wallet Created the previous stepLifetime of Credential Offer
as600
-
Add schemas by clicking on "Add new item" under
Supported Schemas
Schema 1 :
- Schema as
Manual Input
, - Credential Type ID as
EventTicketVC
- JSON Schema URL as
https://schema.affinidi.io/TEventTicketVCV1R0.json
- JSDON-LD Context URL as
https://schema.affinidi.io/TEventTicketVCV1R0.jsonld
You should expect to see the message Issuance configuration has been created successfully. on the Developer portal to confirm the configuration setup is complete.
- Schema as
-
Tip
You can create your own schema using by navigating to Affinidi Schema Builder
under the Services
section. For more details on Schema Builder
refer to Affinidi documentation.
Warning
Ensure the NEXT_PUBLIC_CREDENTIAL_TYPE_ID
value in the application's .env
file matches the Credential Type ID.
-
On the checkout page, post purchase of the ticket, we are going to issue a ticket as Verifiable Credential.
-
Open
src\components\Checkout\index.tsx
and add the below functionIssueTicketVC
(beforehandlePay
event handler)This function performs the following tasks:
- Prepares event ticket credential data from the purchased ticket details
- Calls Eventi's Application API
/api/issuance/start
(we are going to create this API endpoint in the next step) to issue an Event Ticket Credential offer URL - Generates Affinidi Vault Claim link from the Offer URL which can be shared with the Affinidi vault.
//Issue a Event Verifiable Credential by calling Application Backend API const IssueTicketVC = async () => { setIsLoading(true); //Prepare Data (the structure should match with Event Ticket VC Schema) //TODO - Few attributes are hardcoded, we can get this during login by updating Login PEX to request more information like name/address/phonenumber/dob etc.. https://docs.affinidi.com/docs/affinidi-vault/affinidi-vault-data/personal-information/ const ticketCredentialData = { event: items.map((item: any) => { return { eventId: item.product.itemid?.toString(), name: item.product.name, location: item.product.location, startDate: item.product.startDate, endDate: item.product.endDate, }; })[0], ticket: items.map((item: any) => { return { ticketId: item.product.itemid?.toString(), ticketType: item.product.name, seat: item.product.description, }; })[0], createdAt: new Date(), attendeeAtrributes: { email: consumer.user.email, firstName: consumer.user.givenName || "John", lastName: consumer.user.familyName || "Doe", dateOfBirth: consumer.user.birthdate || "2010-10-17", }, secrete: date, }; //Call API to start VC issuance const response = await fetch("/api/issuance/start", { method: "POST", body: JSON.stringify({ credentialData: ticketCredentialData, credentialTypeId: eventTicketVCTypeID, claimMode: StartIssuanceInputClaimModeEnum.FixedHolder, }), headers: { "Content-Type": "application/json", }, }); if (!response.ok) { console.log("Error in issuing credential"); return; } let dataResponse = await response.json(); console.log("dataResponse", dataResponse); setIsLoading(false); //Generate claim link to affinidi vault from offer URL if (dataResponse.credentialOfferUri) { const vaultLink = VaultUtils.buildClaimLink( dataResponse.credentialOfferUri ); setVaultLink(vaultLink); setIssuanceResponse(dataResponse); } console.log("issuanceResponse", issuanceResponse); }
-
Call the function
IssueTicketVC()
on thehandlePay
function -
Update
handlePay
event handler function by callingIssueTicketVC()
which prepares the event ticket VC data and invoke the Affinidi Credentials Issuance Service.
//Event handler on successful payment
const handlePay = () => {
//Payment logic here
....
// Call Issuance service
IssueTicketVC();
};
Create API Endpoint /api/issuance/start
which we have used in IssueTicketVC()
function
Add the issuance logic in the API Handler src\pages\api\issuance\start.ts
//Add VC Issuance Logic here
const { credentialTypeId, credentialData, claimMode } =
issuanceStartSchema.parse(req.body);
const session = await getServerSession(req, res, authOptions);
const holderDid = session?.userId;
//Holder DID is required if Claim mode is FIXED_HOLDER
if (!holderDid && claimMode == StartIssuanceInputClaimModeEnum.FixedHolder) {
res.status(400).json({
message: "Holder DID is required in FIXED_HOLDER claim mode",
});
return;
}
//Prepare the data for issuance
const apiData: StartIssuanceInput = {
claimMode,
...(holderDid && { holderDid }),
data: [
{
credentialTypeId,
credentialData: {
...credentialData,
},
},
],
};
//Initialize the Affinidi TDK with Personal Access Token(PAT) details
const authProvider = getAuthProvider();
//Initialise the Affinidi Issuance API Object
const api = new IssuanceApi(
new Configuration({
apiKey: authProvider.fetchProjectScopedToken.bind(authProvider),
})
);
//Start Issuance
const issuanceResponse = await api.startIssuance(projectId, apiData);
// Reading issuance offer
const { credentialOfferUri, txCode, issuanceId, expiresIn } =
issuanceResponse.data;
res.status(200).json({ credentialOfferUri, txCode, issuanceId, expiresIn });
Run The application to experience Affinidi Credentials Issuance
Try the App with Affinidi Login & Affinidi Credential Issuance Service, by purchasing an event ticket and redeem the event ticket in your Affinidi Vault.
npm run dev
Open http://localhost:3000 with your browser to see the result .
Congratulations! You’ve experienced how to issue Event ticket as W3C Verifiable Credentials to the user’s Affinidi Vault. The user would now be able to manage and reuse this information without dependency on the Eventi application. In the next module, you’ll dive deeper, on how a relying application like Event access management software can request this digitally signed file from the user directly without reliance on intermediaries using Open Identity protocol (OID4VP) to establish trust that the user is the rightful owner of this ticket. You will also learn how the developer experience is simplified by Affinidi Iota Framework reducing the lines of code and effort required for applciation developers to adopt this emerging technology in their application.