# Sample app with WebSocket implementation

> Use this guide to set up and run a Next.js sample application that integrates with Affinidi Iota Framework using WebSocket mode.

WebSocket mode enables a consent-driven data-sharing flow where requests and responses are processed through a WebSocket channel created when the Iota Session is initialised.

Applications using WebSocket mode must implement Affinidi Login to parse the user’s Decentralised Identifier (DID). This DID is required to generate the signed request token and ensure only the authenticated user can access Iota Credentials, protecting against phishing and forwarding attacks.

## Before you begin

Ensure you have:

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

        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.

- Affinidi CLI installed. Follow the guide below if not 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
```

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

- 
[NodeJS](https://nodejs.org/en/download) installed on your machine.

## Download the application

Download the sample code as a ZIP from the [GitHub Repo](https://github.com/affinidi/reference-app-affinidi-vault/tree/main/samples/affinidi-nextjs-nextauthjs) or generate it using Affinidi CLI:

```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 app dependencies

After successfully generating the sample app, n avigate to the affinidi-sample-app directory and install dependencies using the following commands:

```Bash
npm install
```

## Run the application

Start the app locally:

```Bash
npm run dev
```

Once it is successfully started, visit the app in your browser using the link [http://localhost:3000](http://localhost:3000).

## Integrate Affinidi Login

Affinidi Iota Framework requires the user’s DID to:

- Generate Iota Credentials

- Sign the Request Token

- Ensure only the authenticated user can access credentials

Implement Affinidi Login for authentication and authorisation.

### 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:

- Default Presentation Definition (presentationDefinition)

- Default ID Token Mapping (idTokenMapping) to request the user’s email during authentication

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.

## Integrate Affinidi Iota Framework

After setting up Affinidi Login, configure the integration to enable data-sharing flow with the Affinidi Iota Framework:

- Configure integration to enable data sharing with Affinidi Iota Framework.

- Create an Affinidi Iota Framework Configuration and define a Presentation Definition for querying data from Affinidi Vault.

Follow [this guide](/products/affinidi-elements/iota-framework/configuration.md) for instructions on creating the configuration.

### Create a personal access token

After creating the configuration and Presentation Definition, generate a Personal Access Token (PAT) using Affinidi CLI:

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

The PAT includes:

- Private/public keys (protected with a passphrase)

- A defined policy granting permissions to call Affinidi Iota Framework

Copy the output and configure it later in the sample app’s environment variables.

Example 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 shown only once.

### Configure the app to integrate with Affinidi TDK

Add PAT details to environment variables.

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 data sharing flow

After setting up the Personal Access Token (PAT) and running the app:

- Open [http://localhost:3000](http://localhost:3000).

- Click Receive Credentials. You can choose:

- The page using WebSocket mode

- The page using Redirect mode

On the Receive Credentials page, you will see a dropdown field listing all the available Affinidi Iota Framework configurations created on your project.

Select the Affinidi Iota Framework configuration, including the method of opening your Affinidi Vault, whether a browser popup or a new tab if you are using WebSocket mode or select the Redirect URL if you are using Redirect mode. Also, select the Query or the Presentation Definition you defined on your configuration to query the data from the Affinidi Vault.

Once all the options are selected, click on the Share button. This will show the consent screen of the Affinidi Vault, which displays the data being requested and asks if you would like to allow access to this data.

## How the integration works

After testing the data-sharing flow, review how the integration works.

The sample app uses Affinidi TDK modules:

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

- [Iota Core](/dev-tools/affinidi-tdk.md#libraries) library to generate the Iota Credentials for signing the Request Token.

- [Iota client](/dev-tools/affinidi-tdk.md#clients) to call Affinidi Iota Framework service to load the configurations.

- [Iota Browser](/dev-tools/affinidi-tdk.md#libraries) library to initialise the Iota Session and prepare the Request Token to request and receive data from the Affinidi Vault.

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

### Generating Iota Credentials for signing request token

The backend exposes an API endpoint to generate Iota Credentials for signing the request token.
This token is used by the frontend to request and receive data from Affinidi Vault.

It uses two modules from Affinidi TDK:

- 
Auth Provider Authenticates and authorises the PAT and generates the Iota Token. Requires:

- Affinidi Iota Framework Configuration ID

- Logged-in user’s DID from Affinidi Login

- 
Iota Core Generates Iota Credentials to sign the request token. Takes the JWT from the Iota Token as a parameter.

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

```TypeScript
try {
    const session = await getServerSession(req, res, authOptions);
    if (!session) {
      res.status(401).json({ message: "You must be logged in." });
      return;
    }
    const { iotaConfigurationId } = iotaStartSchema.parse(req.query);

    const authProvider = getAuthProvider();
    const iotaToken = authProvider.createIotaToken(
      iotaConfigurationId,
      session.userId,
    );
    const iotaCredentials = await Iota.limitedTokenToIotaCredentials(
      iotaToken.iotaJwt,
    );

    res.status(200).json(iotaCredentials);
} catch (error: any) {
    res.status(500).json({ message: "Unable to get Iota credentials" });
    console.log(error);
}
```

### Initialising Affinidi Iota Framework session

After setting up the API endpoint to generate the Iota Credentials, in the front end, we shall initialise the IotaSession using the Iota Browser package of the Affinidi TDK.
Important Note

The Affinidi TDK’s Iota Browser library is a browser-only module that creates a WebSocket connection and requires access to the browser window object to initiate a data request for the Affinidi Vault.

If you are using a framework with a server-side rendering like NextJS, you can refer to [this guide](/dev-tools/affinidi-tdk.md#libraries#implementation-note).

In our sample application, the IotaSession is initialised whenever you select an Affinidi Iota Framework configuration from the dropdown list.

You may refer to the configurationsQuery query for the sample code to load the list of configurations from your project using the Iota client of the Affinidi TDK.

Source Path: src/components/iota/IotaClientPage.tsx

```TypeScript
async function getIotaCredentials(configurationId: string) {
    const response = await fetch(
      "/api/iota/start?" +
      new URLSearchParams({
        iotaConfigurationId: configurationId,
      }),
      {
        method: "GET",
      },
    );
    return (await response.json()) as IotaCredentials;
}
```

The IotaSession is initialised through the [useQuery](https://tanstack.com/query/v4/docs/framework/react/reference/useQuery) hook that gets triggered when selecting a Configuration from the dropdown list.

```TypeScript
const iotaSessionQuery = useQuery({
    queryKey: ["iotaSession", selectedConfigId],
    queryFn: async ({ queryKey }) => {
      const credentials = await getIotaCredentials(queryKey[1]);
      const iotaSession = new Session({ credentials });
      await iotaSession.initialize();
      return iotaSession;
    },
    enabled: !!selectedConfigId,
});
```

Before initialising:

- Call getIotaCredentials to fetch credentials from the API endpoint.

- Pass credentials to IotaSession to start the session.

The IotaSession opens a WebSocket connection and listens to the callback events.

### Handling the data sharing request

To trigger the flow:

- Use an async function handleTDKShare to prepare and sign the request token.

- Pass the Query ID (Presentation Definition) to request data from Affinidi Vault.

Source Path: src/components/iota/IotaClientPage.tsx

```TypeScript
async function handleTDKShare(queryId: string) {
    if (!iotaSessionQuery.data) {
      throw new Error("Iota session not initialized");
    }
    try {
      setIsFormDisabled(true);
      const request = await iotaSessionQuery.data.prepareRequest({ queryId });
      setIsFormDisabled(false);
      addNewDataRequest(request);
      request.openVault({ mode: openMode });
      const response = await request.getResponse();
      updateDataRequestWithResponse(response);
    } catch (error) {
      if (error instanceof IotaError) {
        updateDataRequestWithError(error);
        console.log(error.code);
      }
    }
}
```

Attach handleTDKShare to the rendered button as an onClick event.

```TypeScript
{iotaSessionQuery.isSuccess && selectedQuery && (
   handleTDKShare(selectedQuery)}
  >
    Share

)}
```

After signing the request token:

- Affinidi Vault opens to query data and request user consent.

- The response returns to the WebSocket opened by IotaSession.

- Use request.getResponse() to parse the response in JSON format.

Here is an example:

```JSON
{
  "correlationId": "b099967b-8736-44db-93fa-a741e8016848",
  "verifiablePresentation": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1"
    ],
    "id": "claimId:gpf1UbjaUwwFtgKUbu_Yj",
    "holder": {
      "id": "did:key:zQ3shPh4UnmNgNza3TB2KkhKDrcEVVnntyjdNWYqDg8jKo6Gj"
    },
    "proof": {
      ...
    },
    "type": [
      "VerifiablePresentation"
    ],
    "verifiableCredential": [
      {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://schema.affinidi.com/EmailV1-0.jsonld"
        ],
        "credentialSchema": {
          "id": "https://schema.affinidi.com/EmailV1-0.json",
          "type": "JsonSchemaValidator2018"
        },
        "credentialSubject": {
          "email": "info@affinidi.com"
        },
        "holder": {
          "id": "did:key:zQ3shPh4UnmNgNza3TB2KkhKDrcEVVnntyjdNWYqDg8jKo6Gj"
        },
        "id": "claimId:31de43221eeb658e",
        "issuanceDate": "2024-07-03T05:05:56.702Z",
        "issuer": "did:key:zQ3shtMGCU89kb2RMknNZcYGUcHW8P6Cq3CoQyvoDs7Qqh33N",
        "proof": {
          ...
        },
        "type": [
          "VerifiableCredential",
          "Email"
        ]
      }
    ]
  },
  "presentationSubmission": {
    "id": "NT080x7PwL3hG2MFxtCor",
    "definition_id": "token_with_email_vc",
    "descriptor_map": [
      {
        "id": "email_vc",
        "path": "$.verifiableCredential[0]",
        "format": "ldp_vc"
      }
    ]
  }
}
```

The verifiableCredential can have multiple entries depending on

- Your Presentation Definition

- Verifiable Credentials shared by the user from Affinidi Vault.
