# Proof-of-Personhood (MeID)

{% hint style="success" %}
his page covers the **Proof-of-Personhood** features of [MeID](https://docs.zk.me/hub/what/zkkyc/meid). If you want to integrate zkKYC, please jump to [](https://docs.zk.me/hub/start/onboarding/integration/js-sdk/zkkyc "mention") for the compliance-focused integration.
{% endhint %}

## Use Case

When you need to protect a website or application from automated attacks, you can use anti-bot mechanisms. These attacks can result in malicious behavior, such as spamming, data theft, or network disruption. Anti-bot technology is designed to identify and block these attacks to ensure that only real human users can access your website or application.

In this case, users are required to undergo facial liveliness detection to prove that they are real human users. This detection requires users to perform specific actions or expressions in front of a camera to prove that they are genuine humans and not automated programs. This technology can help prevent automated attacks and fraud, and increase the security and reliability of your website or application.

***

## **zkMe-Widget MeID Process**

**Step 1:** Enter the service authorization Widget page; the user confirms and goes to the next step

**Step 2:** E-mail verification login / Wallet address login

**Step 3:** Verify that the user has authorized MeID

**Step 4:** Based on the outcomes of the initiated query, a determination is made regarding whether to commence the authentication process for the specified user.

***

## Interaction Instructions

<figure><img src="https://content.gitbook.com/content/3QFkeleLOltSYnf8uj0t/blobs/a3Ra4elhqlRBv63nkGh4/20230322(2).png" alt=""><figcaption></figcaption></figure>

***

## Integration via NPM

You can refer to [@zkmelabs/widget](https://www.npmjs.com/package/@zkmelabs/widget?activeTab=versions) and please make sure to use the latest version.

### Installation

```sh
pnpm add @zkmelabs/widget

# or
yarn add @zkmelabs/widget

# or
npm install @zkmelabs/widget
```

### Getting Started

#### **Step 1. Import styles**

```typescript
import '@zkmelabs/widget/dist/style.css'
```

#### **Step 2. Create a new `ZkMeWidget` instance**

{% tabs %}
{% tab title="Email Login Mode" %}
{% code expandable="true" %}

```typescript
import { ZkMeWidget, type Provider } from '@zkmelabs/widget'

const provider: Provider = {
  async getAccessToken() {
    // -------------------------TODO-------------------------
    // Request a new token from your backend service and return it to the widget.
    // For the access token, see https://docs.zk.me/hub/start/onboarding/integration/js-sdk/zkkyc/meid#access-token
    // ------------------------------------------------------
    return fetchNewToken()
  },

  async getUserAccounts() {
    // -------------------------TODO-------------------------
    // If your project is a Dapp,
    // you need to return the user's connected wallet address.
    const userConnectedAddress = await connect()
    return [userConnectedAddress]

    // If not,
    // you should return the user's e-mail address, phone number or any other unique identifier.
    //
    // return ['email address']
    // or
    // return ['phone number']
    // or
    // return ['unique identifier']
    // ------------------------------------------------------
  },

}

const zkMeWidget = new ZkMeWidget(
  // -------------------------TODO-------------------------
  appId, // This parameter means the same thing as "mchNo"
  'YourDappName',
  chainId,
  provider,
  {
      lv: 'MeID'
      // For other options, please refer to the table below
  }
  // ------------------------------------------------------
)
```

{% endcode %}
{% endtab %}

{% tab title="Wallet Login Mode" %}
{% code expandable="true" %}

```typescript
import { ZkMeWidget, type Provider } from '@zkmelabs/widget'

const provider: Provider = {
  async getAccessToken() {
    // -------------------------TODO-------------------------
    // Request a new token from your backend service and return it to the widget.
    // For the access token, see docs.zk.me/zkme-dochub/meid-anti-bot-suite/meid-integration-guide/sdk-integration#how-to-generate-an-access-token-with-api_key
    // ------------------------------------------------------
    return fetchNewToken()
  },

  async getUserAccounts() {
    // If your project is a Dapp,
    // you need to return the user's connected wallet address.
    const userConnectedAddress = await connect()
    return [userConnectedAddress]
  },

}

const zkMeWidget = new ZkMeWidget(
  // -------------------------TODO-------------------------
  appId, // This parameter means the same thing as "mchNo"
  'YourDappName',
  chainId,
  provider,
  {
      lv: 'MeID',
      mode: 'wallet',
      // Whether to verify the validity of the user's wallet. Default is false. 
      // If set to true, you need to implement the provider.signMessage method.
      checkAddress: true 
      // For other options, please refer to the table below
  }
  // ------------------------------------------------------
)
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**NOTE:** The specific configuration for the "option" parameter is shown in the table below
{% endhint %}

<table><thead><tr><th width="196">Param</th><th width="164">Type</th><th>Description</th></tr></thead><tbody><tr><td>options.theme</td><td>Theme?</td><td><code>"auto"</code>, <code>"light"</code> or <code>"dark"</code>, default <code>"auto"</code>. </td></tr><tr><td>options.locale</td><td>Language?</td><td><code>"en"</code> or <code>"zh-hk"</code>, default <code>"en"</code>.</td></tr></tbody></table>

#### **Step 3. Listen to the `meidFinished` widget event to detect when the user has completed the MeID process**

```typescript
function handleFinished(results) {
  const { isGrant, associatedAccount } = results

  if (
    isGrant &&
    associatedAccount === userConnectedAddress.toLowerCase()
  ) {
    // Prompts the user that MeID verification has been completed
  }
}

zkMeWidget.on('meidFinished', handleFinished)
```

#### **Step 4. Launch the zkMe widget and it will be displayed in the center of your webpage**

```typescript
// This is the code to launch our widget on your page
button.addEventListener('click', () => {
  zkMeWidget.launch()
})
```

***

## Helper functions

### verifyMeidWithZkMeServices()

Before launching the widget, you should check the MeID status of the user and launch the widget when the check result is `false`.

```typescript
import { verifyMeidWithZkMeServices } from '@zkmelabs/widget'

// MeID
const { isGrant } = await verifyMeidWithZkMeServices(
  appId,
  userAccount
)
```

<table><thead><tr><th width="191">Param</th><th width="98">Type</th><th>Description</th></tr></thead><tbody><tr><td>appId</td><td>string</td><td>This parameter means the same thing as "mchNo"</td></tr><tr><td>userAccount</td><td>string</td><td>The <code>userAccount</code> info (such as wallet address, email, phone number, or unique identifier) must match the format of accounts returned by <code>provider.getUserAccounts</code>.</td></tr></tbody></table>

## **How to Generate an Access Token with API\_KEY**

To use your API\_KEY to obtain an accessToken, you will need to make a specific HTTP request. Here's how you can do it:

#### a. **Endpoint**: Send a <mark style="color:orange;">`POST`</mark> request to the token exchange endpoint.

```powershell
POST https://nest-api.zk.me/api/token/get
```

{% hint style="info" %}
Please remember to modify the <mark style="color:blue;">`Content-Type`</mark> in the request header to <mark style="color:blue;">`application/json`</mark>. Failing to do so might result in a <mark style="color:red;">`Parameter Error`</mark> response.
{% endhint %}

#### b. **Request Body**:

<table><thead><tr><th width="193">Parameter Name</th><th width="101">Required</th><th width="96">Type</th><th>Desc</th></tr></thead><tbody><tr><td>apiKey</td><td>True</td><td>string</td><td>The API_KEY provided by zkMe.</td></tr><tr><td>appId</td><td>True</td><td>string</td><td>A unique identifier (mchNo) to DApp provided by zkMe.</td></tr><tr><td>apiModePermission</td><td>True</td><td>number</td><td>0 - email login <br>1 - wallet address login</td></tr><tr><td>lv</td><td>True</td><td>number</td><td>The parameter must be passed and always be 2.</td></tr></tbody></table>

{% hint style="info" %} <mark style="color:orange;">`API_KEY`</mark>can be found in [the Configuration section](https://dashboard.zk.me/integration) of the Integration on the zkMe Dashboard.
{% endhint %}

#### c. **Response**

<details>

<summary><mark style="color:green;"><strong>Success</strong></mark></summary>

<pre class="language-json"><code class="lang-json">{
    "code": 80000000,
    "data": {
        "accessToken": "8641259808779c53de65c3698e42b402b112cfe3856202189c37eae9f0b23babbcc1429ea9adcb52283dca4dab024a640651f855d8c78c7bde308f721a6e0cb80d51dab7c775ebfe0ae74eb9ab02f503094a9b2a2e2aeabf70e03a0cac9773a93dba743ca0dc3fa4af77375351bc48f76515d72dbee3a8bd5c034e6ffb94bd97"
<strong>    },
</strong>    "msg": "success",
    "timestamp": 1691732474552
}
</code></pre>

</details>

<details>

<summary><mark style="color:red;"><strong>Exception (AppId and API_KEY not matched)</strong></mark></summary>

```json
{
    "code": 81000014,
    "data": null,
    "msg": "AppID and API Key do not match. Access token generation failed",
    "timestamp": 1691732568774
}
```

</details>

<details>

<summary><mark style="color:red;"><strong>Exception (Parameter Error)</strong></mark></summary>

```json
{
    "code": 80000002,
    "data": null,
    "msg": "parameter error",
    "timestamp": 1691732593484
}
```

</details>

<details>

<summary><mark style="color:red;"><strong>Exception (System Error)</strong></mark></summary>

```json
{
    "code": 80000001,
    "data": null,
    "msg": "system error",
    "timestamp": 1691732593484
}
```

</details>

***

## ZkMeWidget instance methods

<details>

<summary>launch()</summary>

Launch the zkMe widget and it will be displayed in the center of your webpage.

<pre class="language-typescript"><code class="lang-typescript"><strong>launch(): void
</strong></code></pre>

</details>

<details>

<summary>on()</summary>

Listen to zkMe widget events.

<pre class="language-typescript"><code class="lang-typescript"><strong>on(event: 'meidFinished', callback: MeidFinishedHook): void;
</strong>on(event: 'close', callback: () => void): void;
</code></pre>

</details>

<details>

<summary>hide()</summary>

Hide the zkMe widget.

```typescript
hide(): void
```

</details>

<details>

<summary>destroy()</summary>

Remove the message event listener registered by the zkMe widget from the window and destroy the DOM node.

```typescript
destroy(): void
```

</details>

***

## **Response & Exceptions**

<details>

<summary><mark style="color:green;">Success</mark></summary>

If the user has passed the liveness and uniqueness verification, the following interface will be seen.

**Note:**

The finished callback function will be fired after the interface is displayed.

<img src="https://content.gitbook.com/content/3QFkeleLOltSYnf8uj0t/blobs/W9gf5kXzTlxzNuZog7Il/Group_48097520.png" alt="" data-size="original">

</details>

<details>

<summary><mark style="color:red;">Camera Permission Denied Error</mark></summary>

The following screen will be displayed for possible issues such as the user denying browser camera access or not having a camera on the device.

<img src="https://content.gitbook.com/content/3QFkeleLOltSYnf8uj0t/blobs/F6Rx4GT2578yDUkclYFn/Frame_48096348.png" alt="" data-size="original">

</details>

<details>

<summary><mark style="color:red;">Face Recognition Error</mark></summary>

The following screen will be displayed for possible problems such as eyes closed detected, art mask detected and etc.

<img src="https://content.gitbook.com/content/3QFkeleLOltSYnf8uj0t/blobs/uzczOa12jUIaTAAFJG0F/Frame_48096348_(1).png" alt="" data-size="original">

</details>

<details>

<summary><mark style="color:red;">Existing Faceprint Error</mark></summary>

The following screen will be displayed for the possible problem that the user’s faceprint is similar to another user’s.

<img src="https://content.gitbook.com/content/3QFkeleLOltSYnf8uj0t/blobs/1U2qzIKaqtr5lJ4qyLBf/1015.png" alt="" data-size="original">

</details>

<details>

<summary><mark style="color:red;">Faceprint Recognition Server Error</mark></summary>

The following screen will be displayed when something goes wrong on the faceprint recognition server.

<img src="https://content.gitbook.com/content/3QFkeleLOltSYnf8uj0t/blobs/npdN7YY6B340bXzYCG5Z/Frame_48096348_(4).png" alt="" data-size="original">

</details>

<details>

<summary><mark style="color:red;">Unknown Error</mark></summary>

The following screen will be displayed when something goes wrong not listed above.

<img src="https://content.gitbook.com/content/3QFkeleLOltSYnf8uj0t/blobs/x6xB004IdK59P9pGaj6p/1014.png" alt="" data-size="original">

</details>
