# Sample application with Credential Issuance

> Use this guide to setup and run the sample application using NextJS that integrates with Credential Issuance service to get you started quickly.

## Before you begin

- Set up Affinidi Vault account. Follow the guide below if you haven’t set it up yet.

        Set up Affinidi Vault

Set up an Affinidi Vault account using the [Web Vault](https://vault.affinidi.com) or install the Mobile Vault (for [Android](https://play.google.com/store/apps/details?id=com.affinidi.vault&pcampaignid=web_share)).

The same setup steps for Mobile Vault.

- 
Click on Get started if you are creating a new account, or click on Restore from Backup if you have an existing backup of your Affinidi Vault. Provide the passphrase to secure your Affinidi Vault.

You have the option to enable Biometrics to unlock your Affinidi Vault easily instead of using passphrase.

GIF 

- Enter your email address to register with the Affinidi Vault. An OTP will be sent to this email for verification.

GIF 

- Enter the OTP sent to the email you have provided for verification to complete the setup.

GIF 

After successfully providing the OTP, you are redirected to the Affinidi Vault dashboard.
Important Note

Remember to keep your passphrase in a secure location. Use the Passphrase Reset feature in Affinidi Vault settings to generate the PDF files and keep them safe, which you can use to recover access to your Affinidi Vault if you forget your passphrase.

- Install the Affinidi CLI. Follow the guide below if it hasn’t been installed.

        Set up Affinidi CLI

- Download and install [NodeJS](https://nodejs.org/en/download) on your machine if you haven’t set it up yet.

Node Version

Affinidi CLI requires Node version 18 and above.

- Install Affinidi CLI using Node Package Manager (npm).

```bash
npm install -g @affinidi/cli
```

- Verify that the installation is successful.

```bash
affinidi --version
```

- 
Make sure you have Git installed on your machine. Follow [this guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) on how to install Git.

- 
Install the [NodeJS](https://nodejs.org/en/download) on your machine if you haven’t set it up yet.

## Download the application

You can download as ZIP file the code sample from the [GitHub Repo](https://github.com/affinidi/reference-app-affinidi-vault/tree/main/samples/affinidi-nextjs-nextauthjs) or generate it using Affinidi CLI with the following command:

```Bash
affinidi generate app --provider=affinidi --framework=nextjs --library=nextauthjs --path=affinidi-sample-app
```

Select n when prompted to Automatically configure sample app environment, we will configure it later.

The above command will generate the code sample in the affinidi-sample-app directory.

    Important Note
    The downloadable sample application is provided only as a guide to quickly explore and learn how to integrate the components of Affinidi Trust Network into your application. This is NOT a Production-ready implementation. Do not deploy this to a production environment.

## Install dependencies

After successfully generating the sample app, go to the affinidi-sample-app directory from your terminal and install the required dependencies using the following commands:

```Bash
npm install
```

## Integrate Affinidi Login

The Credential Issuance requires the Decentralised Identifier (DID) of the user to set the Holder DID (holderDid) as a parameter when creating a Credential Offer. To get the User DID, we will implement Affinidi Login to authenticate and extract the user DID value from the ID Token provided.

### Create login configuration

Name: Affinidi Sample App

Redirect URIs: http://localhost:3000/api/auth/callback/affinidi

        Using Affinidi CLI

- Log in to Affinidi CLI by running:

```Bash
affinidi start
```

- Once you have successfully logged in, create the Login Configuration by running:

```Bash
affinidi login create-config --name='Affinidi Sample App' --redirect-uris='http://localhost:3000/api/auth/callback/affinidi'
```

- --name is what you want your login configuration to be called.

- --redirect-uris is the URL on your application where the user gets redirected after the successful authentication.

Learn more on how to manage your Login Configurations using [Affinidi CLI](/dev-tools/affinidi-cli/manage-login.md).

        Using Affinidi Portal

- 
Go to [Affinidi Login ](https://portal.affinidi.com/affinidiLogin) under the Services section.

- 
Click on the Create Login Configuration and provide the required details.

- Name is the string that describes your login configuration.

- Redirect URIs is the URL on your application where the user gets redirected after the successful authentication.

- 
Click on create and confirm if all the details are correct.

- 
After confirming the details, another popup shows the Client ID and Client Secret for your Login Configuration. Copy the generated Client Credentials and use them to integrate with Affinidi Login.

- After copying the Client ID and Client Secret and closing the popup, you are redirected back to the Affinidi Login page.

Login Configuration uses the default Presentation Definition (presentationDefinition) and ID Token Mapping (idTokenMapping) that is used to request the user’s email address during the authentication flow.

Learn more about customising the Presentation Definition and ID Token using [this guide](/products/affinidi-elements/affinidi-login/presentation-definition-id-token-mapping.md).

    Important

Safeguard the Client ID and Client Secret diligently; you'll need them for setting up your IdP or OIDC-compliant applications. Remember, the Client Secret will be provided only once.

### Configure the app to enable Affinidi Login

Once the Login Configuration is created, set up the client credentials provided to integrate Affinidi Login.

Copy and set up the environment variables:

```Bash
cp .env.example .env
```

Set the following variables with the values provided by the Login Configuration:

```Bash
PROVIDER_CLIENT_ID=""
PROVIDER_CLIENT_SECRET=""
PROVIDER_ISSUER=""
```

The <LoginConfig.auth.*> are values from Login Configuration.

### Run the application

After installing the dependencies and setting up the required details in the application, run the following command to start the app locally:

```Bash
npm run dev
```

Once it is successfully started, visit the app using the link [http://localhost:3000](http://localhost:3000) and click on the Affinidi Login button to test if the Affinidi Login flow is working.

## Implement Credential Issuance

After successfully setting up the Affinidi Login, let’s configure the integration to enable credential issuance flow.

### Set up Credential 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 ](https://portal.affinidi.com/schemaManager) 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](/products/affinidi-elements/wallets.md).

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](/products/affinidi-elements/schema-builder.md).

The Credential Configuration ID specified on each supported schema is used as a reference when creating a Credential Offer.

- After setting the fields and providing the list of the supported schema, click Create.

Note

Currently, the Credential Issuance Service only supports one Issuance Configuration per Project.

### Create a personal access token

After creating the Credential Issuance configuration and the selecting the supported Schemas to issue credential to the the Affinidi Vault, we’ll create a Personal Access Token (PAT), a machine user that authenticates to the services and performs actions on your behalf.

To create a Personal Access Token (PAT), run the following Affinidi CLI command:

```Bash
affinidi token create-token -n IssuanceToken --auto-generate-key --passphrase "MySecretPassphrase" --with-permissions
```

The above command will create a Personal Access Token (PAT), including private/public keys protected with a passphrase and a defined policy to grant the PAT permission to perform actions on your behalf, in this case, calling Credential Issuance service.

Copy the command output, and we’ll configure it later on the environment variables of the sample application - the sample output of the command:

```Bash
{
  "tokenId": "086b64ce-oau0-huy7-9876-65d76e84fa36",
  "projectId": "cba41b90-34bg-jhg9-acgf-800baa9a40a0",
  "privateKey": "...",
  "passphrase": "MySecretPassphrase"
}
```
Important Note

Keep your private key and passphrase secured; you’ll need them to integrate with Affinidi TDK. Remember, the Private Key and Passphrase will be provided only once.

### Configure the app to integrate with Affinidi TDK

Let’s configure the Personal Access Token (PAT) details into the environment variables of the sample application.

Set the following variables with the values provided by the Personal Access Token (PAT):

```Bash
PROJECT_ID="

"
TOKEN_ID="

"
PRIVATE_KEY="

"
PASSPHRASE="

"
```

Keep the PUBLIC_KEY and KEY_ID in env file empty.

### Try the Credential Issuance flow

After successfully setting up the Personal Access Token (PAT) details and running the application, go to the web page at  http://localhost:3000 and click the Issue Credentials page. At this point, you should have already been logged in. If you are not yet logged in, click on the Affinidi Login button.

On the Issue Credentials page, you will see your Decentralised Identifier (DID) from the ID Token of Affinidi Login and a dropdown field listing all the available Credential Issuance configurations created on your project.

Select the Credential Issuance configuration, including the Claim Mode on how the user can claim the credential, whether a TX_CODE that generates a Transaction Code that users must enter to claim the credential or a normal mode without Transaction Code required. Also, select the Schema from the Supported Schema listed on your configuration to create a credential offer.

The page will dynamically render the fields based on the selected Schema to enter the details for the credential.

GIF 

## How the integration works

After configuring and testing the credential issuance flow from the sample app, let’s review the codes and how they work to enable this flow.

We are using Affinidi TDK and some of its modules to enable this.

- 
[Auth Provider](/dev-tools/affinidi-tdk.md#packages) package to authenticate and authorise the Personal Access Token (PAT) to perform actions on your behalf.

- 
[Credential Issuance client](/dev-tools/affinidi-tdk.md#libraries) library to integrate with the Credential Issuance service of Affinidi Elements.

Read more about Affinidi TDK [here](/dev-tools/affinidi-tdk.md).

### Handle credential data submission

The frontend implementation of the Credential Issuance calls a client library that triggers credential issuance based on the selected configuration, claim mode, and the Schema. The credential data is based on the list of fields of the selected Schema from the list of supported schemas.

Source Path: src/pages/credential-issuance.tsx

```TypeScript
const handleSubmit = async (credentialData: any) => {
    console.log("credentialData:", credentialData);
    if (
      !holderDid &&
      claimMode == StartIssuanceInputClaimModeEnum.FixedHolder
    ) {
      setMessage({
        message: "Holder DID is required in FIXED_DID claim mode",
        type: "error",
      });
      return;
    }
    setIsFormDisabled(true);
    const response = await fetch("/api/issuance/start", {
      method: "POST",
      body: JSON.stringify({
        holderDid,
        credentialData,
        credentialTypeId: selectedTypeId,
        claimMode,
      }),
      headers: {
        "Content-Type": "application/json",
      },
    });
    if (!response.ok) {
      clearIssuance();
      setMessage({
        message: "Error creating offer",
        type: "error",
      });
      return;
    }
    let dataResponse = await response.json();

    if (dataResponse.credentialOfferUri) {
      setOffer(dataResponse);
    }
    console.log("Offer", offer);
};
```

### Prepare Credential Issuance payload

A backend implementation of the Credential Issuance flow exposes an API endpoint that takes the selected configurations, including the credential data provided from the front end and prepares the payload. This endpoint verifies if an active user session was created from the Affinidi Login authentication flow.

The user session contains the Decentralised Identifier (DID) of the logged-in user and is added as part of the payload to set the recipient of the credential offer.

Source Path: src/pages/api/issuance/start.ts

```TypeScript
try {
    const { credentialTypeId, credentialData, claimMode, holderDid } =
      issuanceStartSchema.parse(req.body);

    const apiData: StartIssuanceInput = {
      claimMode,
      ...(holderDid && { holderDid }),
      data: [
        {
          credentialTypeId,
          credentialData: {
            ...credentialData,
            // Add any additional data here
          },
        },
      ],
    };

    const issuanceResult = await startIssuance(apiData);
    res.status(200).json(issuanceResult);
} catch (error: any) {
    res.status(500).json({ message: "Unable to start issuance" });
    console.log(error);
}
```

### Create a credential offer

After preparing the payload to create a credential offer, the endpoint from the previous section calls the Credential Issuance client to trigger the issuance flow and create a credential offer. In this client file, we have created an async function that generates an authorisation token through the AuthProvider package and initialises the Credential Issuance client of the Affinidi TDK.

Source Path: src/lib/clients/credential-issuance.ts

```TypeScript
export async function startIssuance(apiData: StartIssuanceInput) {
    const authProvider = getAuthProvider();
    const api = new IssuanceApi(
        new Configuration({
        apiKey: authProvider.fetchProjectScopedToken.bind(authProvider),
        }),
    );
    const { data } = await api.startIssuance(projectId, apiData);
    return data;
}
```

The api.startIssuance will return the credential offer details in JSON format. This contains the credentialOfferUri, the txCode if you selected TX_CODE as claim mode, and the credential offer’s lifetime.

```JSON
{
  "credentialOfferUri": "https://

.apse1.issuance.affinidi.io/offer/3da42adc-5412-413b-986c-99c43cb87eba",
  "txCode": "123456",
  "issuanceId": "3da42adc-5412-413b-986c-99c43cb87eba"
  "expiresIn": 3600
}
```

The Affinidi Vault user must claim the credential offer before it expires; otherwise, you will have to create another credential offer.

### Generate claim link

After creating the credential offer, you can send the claim link via email or QR code to allow the recipient of the credential offer to claim the credential and store it on their Affinidi Vault. The claim link will be in the following format with the URL encoded <CREDENTIAL_OFFER_URI> value:

```html
https://vault.affinidi.com/claim?credential_offer_uri=
```

If the Credential Offer was created with the Transaction Code (txCode), the developer must also send it to the user to claim the credentials.

In this example, we have created another component called Offer that generates the claim link using the [VaultUtils](/dev-tools/affinidi-tdk.md#packages#vaultutils) of Affinidi TDK’s common package.

Source Path: src/components/issuance/Offer.tsx

```TypeScript
const vaultLink = VaultUtils.buildClaimLink(offer.credentialOfferUri)
```

Click on the displayed link to open your Affinidi Vault to claim the credential and store it on your selected profile in the Affinidi Vault. Read more about Claimed credentials [here](/products/affinidi-elements/affinidi-vault/claimed-credentials.md).
