# Sample app with redirect implementation

> Use this guide to set up and run a Next.js sample application that integrates with Affinidi Iota Framework using Redirect mode. This helps you get started quickly.

Redirect mode enables a consent-driven data-sharing flow without requiring Affinidi Login. It uses a Redirect URL to generate a signed request token and initiate data sharing.

## Before you begin

Ensure you have:

- 
An Affinidi Vault account. Follow this guide 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 nstalled.

        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.

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

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

Navigate to the affinidi-sample-app directory and install dependencies:

```Bash
npm install
```

## 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).

## Integrate Affinidi Iota Framework

To integrate the Affinidi Iota Framework on your website to enable data-sharing flow using Redirect flow, you must:

- create the Affinidi Iota Framework Configuration

- define a Presentation Definition to query the user data from the Affinidi Vault.

To learn more about Affinidi Iota Framework Configuration and a guide on creating it, visit [this page](/products/affinidi-elements/iota-framework/configuration.md).

### Create a personal access token

After creating the Affinidi Iota Framework configuration and the Presentation Definition to query the data from 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 IotaToken --auto-generate-key --passphrase "MySecretPassphrase" --with-permissions
```

The above command will create a Personal Access Token (PAT).

The PAT includes:

- Private/public keys (protected with a passphrase)

- A defined policy granting permissions to call Affinidi Iota Framework

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

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 secure. They are shown 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 data sharing flow

After setting up PAT and running the app:

- Go to [http://localhost:3000](http://localhost:3000).

- Click Receive Credentials.

- 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.

- The Redirect URL for Redirect mode.

- The Presentation Definition you created to query data.

- Click Share. 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

The sample app uses Affinidi TDK modules, let’s review these:

- [Auth Provider](/dev-tools/affinidi-tdk.md#packages): Authenticates and authorises the PAT.

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

- [Common](/dev-tools/affinidi-tdk.md#packages): Builds the share link and redirects the user to Affinidi Vault.

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

### Generating a signed request token

The backend exposes an API endpoint that generates the signed 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 Personal Access Token (PAT) configured earlier. Calls the Iota client to initiate the data-sharing request. The request requires:

- 
Affinidi Iota Framework Configuration ID

- 
Redirect URL

- 
Iota client: Initiates the data-sharing request and parses the signed request token.
This token is used to redirect the user to Affinidi Vault.

Source Path: src/lib/clients/iota.ts

```TypeScript
export async function initiateDataSharingRequest(
  configurationId: string,
  queryId: string,
  redirectUri: string,
  nonce: string
) {
  const authProvider = getAuthProvider();
  const api = new IotaApi(
    new Configuration({
      apiKey: authProvider.fetchProjectScopedToken.bind(authProvider),
      basePath: `${apiGatewayUrl}/ais`,
    })
  );

  const { data: dataSharingRequestResponse } =
    await api.initiateDataSharingRequest({
      configurationId,
      mode: IotaConfigurationDtoModeEnum.Redirect,
      queryId,
      correlationId: uuidv4(),
      nonce,
      redirectUri,
  });

  const { correlationId, transactionId, jwt } =
    dataSharingRequestResponse.data as InitiateDataSharingRequestOKData;
  return { correlationId, transactionId, jwt };
}
```

### Initialising data sharing request

After setting up the API endpoint:

- Initialise the page in the frontend.

- Fetch the signed request token.

- Redirect the user to Affinidi Vault.

In the sample app:

- The handleRedirectFlowShare function runs when you select an Affinidi Iota Framework configuration from the dropdown.

Refer to the configurationsQuery query or sample code to load configurations using the Iota client of the Affinidi TDK.

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

```TypeScript
async function handleRedirectFlowShare(queryId: string) {
    setIsFormDisabled(true);

    const response = await fetch("/api/iota/init-share", {
      method: "POST",
      body: JSON.stringify({
        configurationId: selectedConfigId,
        queryId,
        redirectUri: selectedRedirectUri,
        nonce,
      }),
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    });

    const data = await response.json();

    const toStore = {
      nonce,
      configurationId: selectedConfigId,
      correlationId: data.correlationId,
      transactionId: data.transactionId,
    };

    localStorage.setItem("iotaRedirect", JSON.stringify(toStore));

    const vaultLink = getShareLink(data.jwt, "client_id");
    router.push(vaultLink);
}
```

After fetching the signed request token:

- Build the share link using VaultUtils from Affinidi TDK’s common package.

- Attach handleRedirectFlowShare to the Share button.

It activates when a configuration is selected.

```TypeScript
function getShareLink(jwt: string, clientId: string) {
    if (typeof window !== "undefined" && window.localStorage) {
      const vaultUrl = window.localStorage.getItem("affinidiVaultUrl");

      if (vaultUrl) {
        return buildShareLinkInternal(vaultUrl, jwt, clientId);
      }
    }

    return VaultUtils.buildShareLink(jwt, clientId);
}
```

The handleRedirectFlowShare is attached to the Share button and is enabled when selecting a Configuration from the dropdown list.

```html
{selectedQuery && (
    <>
        Generated nonce: {nonce}

         handleRedirectFlowShare(selectedQuery)}
        >
        Share

)}
```

The user is then redirected to Affinidi Vault:

- The consent screen displays requested data.

- The user can approve or deny access.

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

```TypeScript
const getIotaResponse = async (params: GetIotaResponseParams) => {
  const response = await fetch("/api/iota/iota-response", {
    method: "POST",
    body: JSON.stringify(params),
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
  });
  return await response.json();
};
```

The Iota Response is fetched from the backend using the response_code sent from the Affinidi Vault.

Source Path: src/lib/clients/iota.ts

```TypeScript
export async function fetchIotaVpResponse(
  configurationId: string,
  correlationId: string,
  transactionId: string,
  responseCode: string
) {
  const authProvider = getAuthProvider();
  const api = new IotaApi(
    new Configuration({
      apiKey: authProvider.fetchProjectScopedToken.bind(authProvider),
      basePath: `${apiGatewayUrl}/ais`,
    })
  );

  const iotaVpResponse: FetchIOTAVPResponseOK = await api.fetchIotaVpResponse({
    configurationId,
    correlationId,
    transactionId,
    responseCode,
  });

  const vp = JSON.parse((iotaVpResponse.data as any).vpToken);
  return { vp: vp, nonce: iotaVpResponse.data.nonce };
}
```

The Verifiable Presentation token vpToken is parsed from the Iota Response, including the nonce value, to verify the request and response. The response is a JSON format, like the sample below:

```JSON
{
  "correlationId": "ab0a1309-bec8-4c28-828f-8a1c7e8ce606",
  "presentationSubmission": {
    "descriptor_map": [
      {
        "id": "email_vc",
        "path": "$.verifiableCredential[0]",
        "format": "ldp_vc"
      }
    ],
    "id": "Ub2yNyMEFlW8ziKMKwVzk",
    "definition_id": "token_with_email_vc"
  },
  "nonce": "6c877dd0-a844-4981-be15-aceed1d2fd5c",
  "vpToken": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1"
    ],
    "type": [
      "VerifiablePresentation"
    ],
    "verifiableCredential": [
      {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://schema.affinidi.com/EmailV1-0.jsonld"
        ],
        "id": "claimId:0ecab5796c9f160b",
        "type": [
          "VerifiableCredential",
          "Email"
        ],
        "holder": {
          "id": "did:key:zQ3shq75QjFhLLeVCC5MATFdSQPrfkDwHoXBUPKGScHSdWi8p"
        },
        "credentialSubject": {
          "email": "info@affinidi.com"
        },
        "credentialSchema": {
          "id": "https://schema.affinidi.com/EmailV1-0.json",
          "type": "JsonSchemaValidator2018"
        },
        "issuanceDate": "2024-07-29T05:25:57.982Z",
        "issuer": "did:key:zQ3shXLA2cHanJgCUsDfXxBi2BGnMLArHVz5NWoC9axr8pEy7",
        "proof": {
          ...
        }
      }
    ],
    "holder": {
      "id": "did:key:zQ3shq75QjFhLLeVCC5MATFdSQPrfkDwHoXBUPKGScHSdWi8p"
    },
    "id": "claimId:O81O9IXOs-uKQcwctMpEb",
    "proof": {
      ...
    }
  }
}
```

The verifiableCredential can have multiple entries depending on the Presentation Definition you defined and the Verifiable Credentials shared by the user from their Affinidi Vault.
