> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/common/authentication/hash-key.md).

# 用户识别键发放

用户识别密钥发放功能可帮助你无需单独的服务器联动或用户同意流程，也能在 Mini App 内稳定识别用户。\
用户进入 Mini App 的瞬间，就会创建该用户的 Mini App 准会员。

{% hint style="info" %}
**Toss 登录迁移**

如果你之前一直通过 Toss 登录识别用户，可以切换为用户识别密钥发放。请参考迁移指南。
{% endhint %}

根据 Mini App 类型，使用的函数不同。

| Mini App 类型 | 函数                  | 说明                        |
| ----------- | ------------------- | ------------------------- |
| 游戏          | `getUserKeyForGame` | 返回游戏 Mini App 专用的用户识别密钥。  |
| 非游戏         | `getAnonymousKey`   | 返回非游戏 Mini App 专用的用户识别密钥。 |

这两个函数都能在无需服务器联动的情况下识别用户， **唯一键值(hash)** 。返回的用户识别码在每个 Mini App 中都是唯一的。

{% hint style="info" %}
**请务必确认**

* 唯一键值(`hash`) 值在同一个 Mini App 中，对同一用户始终返回相同的值。
* 即使删除 App 或更换设备，只要是同一用户，返回的值也相同。
* 各函数只能在对应类别的 Mini App 中使用。如果在错误的类别中调用，会发生错误。
* 在 Sandbox 中会返回 mock 数据，请通过二维码测试。
  {% endhint %}

***

### 游戏 Mini App

**SDK 函数：** `getUserKeyForGame`

`getUserKeyForGame`是用于在游戏 Mini App 中识别用户的专用 API。与 Toss 登录类似，无需单独的认证页面或服务器联动，就能直接在游戏 Mini App 内获取唯一的用户识别码。

该函数 **只能在游戏类别 Mini App 中使用**，返回的用户识别码（`hash`) 也 **在各个 Mini App（游戏）中唯一**。这个值可用于游戏内数据存储、排行榜管理等。

{% hint style="info" %}
**请注意**

* 该函数 **只能在游戏类别 Mini App 中使用**。如果在非游戏 Mini App 中调用， `'INVALID_CATEGORY'` 会返回。
* **仅支持 Toss App 5.232.0 及以上**。低于该版本时， `undefined` 会返回。
* 为了稳定提供所有用户的识别码， **游戏 Mini App 的最低支持 Toss App 版本已提升至 5.232.0**。
  * 在低于支持版本时，进入 Mini App 会显示更新提示页面。
* 在 Sandbox 环境中会 **mock 数据**返回。实际行为请通过二维码在 Toss App 中测试。
  {% endhint %}

**签名**

```typescript
function getUserKeyForGame(): Promise<GetUserKeyForGameSuccessResponse | 'INVALID_CATEGORY' | 'ERROR' | undefined>;
```

**返回值**

* `Promise<GetUserKeyForGameSuccessResponse | 'INVALID\_CATEGORY' | 'ERROR' | undefined>`

  返回用户密钥查询结果。
* `GetUserKeyForGameSuccessResponse`：用户密钥查询成功。 `{ type: 'HASH', hash: string }` 形式返回。
  * `hash` 该值是仅在对应游戏 Mini App 内有效的用户识别码。
* `'INVALID_CATEGORY'`：在非游戏类别的 Mini App 中调用。
* `'ERROR'`：发生了未知错误。
* `undefined`：App 版本低于最低支持版本。

**示例：获取游戏用户识别码**

下面的示例展示了在游戏 Mini App 中 `getUserKeyForGame`调用该函数，获取并处理用户识别码的基本流程。

{% tabs %}
{% tab title="js" %}

```js
import { getUserKeyForGame } from '@apps-in-toss/web-framework';

async function handleGetUserKey() {
  const result = await getUserKeyForGame();

  if (!result) {
    console.warn('不支持的 App 版本。');
  } else if (result === 'INVALID_CATEGORY') {
    console.error('这是非游戏类别的 Mini App。');
  } else if (result === 'ERROR') {
    console.error('查询用户密钥时发生了错误。');
  } else if (result.type === 'HASH') {
    console.log('用户密钥：', result.hash);
    // 可以在这里使用用户密钥管理游戏数据。
  }
}
```

{% endtab %}

{% tab title="React" %}

```tsx
import { getUserKeyForGame } from '@apps-in-toss/web-framework';

function GameUserKeyButton() {
  async function handleClick() {
    const result = await getUserKeyForGame();

    if (!result) {
      console.warn('不支持的 App 版本。');
      return;
    }

    if (result === 'INVALID_CATEGORY') {
      console.error('这是非游戏类别的 Mini App。');
      return;
    }

    if (result === 'ERROR') {
      console.error('查询用户密钥时发生了错误。');
      return;
    }

    if (result.type === 'HASH') {
      console.log('用户密钥：', result.hash);
      // 可以在这里使用用户密钥管理游戏数据。
    }
  }

  return <button onClick={handleClick}>获取用户密钥</button>;
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { Button } from 'react-native';
import { getUserKeyForGame } from '@apps-in-toss/framework';

function GameUserKeyButton() {
  async function handlePress() {
    const result = await getUserKeyForGame();

    if (!result) {
      console.warn('不支持的 App 版本。');
      return;
    }

    if (result === 'INVALID_CATEGORY') {
      console.error('这是非游戏类别的 Mini App。');
      return;
    }

    if (result === 'ERROR') {
      console.error('查询用户密钥时发生了错误。');
      return;
    }

    if (result.type === 'HASH') {
      console.log('用户密钥：', result.hash);
      // 可以在这里使用用户密钥管理游戏数据。
    }
  }

  return <Button onPress={handlePress} title="获取用户密钥" />;
}
```

{% endtab %}
{% endtabs %}

**参考事项**

* `getUserKeyForGame`是游戏 Mini App 专用的登录/识别手段。
* Toss 登录(`appLogin`) 不同，它无需与服务器 API 联动也能使用。
* 建议以该用户密钥为基准管理游戏用户数据（排行榜、积分、存档数据等）。

***

### 非游戏 Mini App

**SDK 函数：** `getAnonymousKey`

`getAnonymousKey`是用于在非游戏 Mini App 中识别用户的 API。与 Toss 登录类似，无需单独的认证页面或服务器联动，就能直接在 Mini App 内获取唯一的用户识别码。

该函数 **只能在非游戏类别 Mini App 中使用**，返回的用户识别码（`hash`) 也 **在每个 Mini App 中都唯一**。

{% hint style="info" %}
**请注意**

* 该函数 **只能在非游戏类别 Mini App 中使用**。如果在游戏 Mini App 中调用， `'INVALID_CATEGORY'` 会返回。
* **SDK 2.4.5 及以上**支持。低于该版本时， `undefined` 会返回。
* 返回的用户密钥是 **不是用于调用 Toss 服务器 API 的密钥。**
  * 仅用于内部用户识别和数据管理。
* 在 Sandbox 环境中会 **mock 数据**返回。实际行为请通过二维码在 Toss App 中测试。
  {% endhint %}

**签名**

```typescript
function getAnonymousKey(): Promise<GetAnonymousKeySuccessResponse | 'INVALID_CATEGORY' | 'ERROR' | undefined>;
```

**返回值**

* `Promise<GetAnonymousKeySuccessResponse | 'INVALID\_CATEGORY' | 'ERROR' | undefined>`

  返回用户密钥查询结果。
* `GetAnonymousKeySuccessResponse`：用户密钥查询成功。 `{ type: 'HASH', hash: string }` 形式返回。
  * `hash` 该值是仅在对应 Mini App 中有效的用户识别码。
* `'INVALID_CATEGORY'`：在非游戏类别的 Mini App 中调用了。
* `'ERROR'`：发生了未知错误。
* `undefined`：SDK 版本低于最低支持版本。

**示例：获取用户识别码**

下面的示例展示了在非游戏 Mini App 中 `getAnonymousKey`调用该函数，获取并处理用户识别码的基本流程。

{% tabs %}
{% tab title="js" %}

```js
import { getAnonymousKey } from '@apps-in-toss/web-framework';

async function handleGetUserKey() {
  const result = await getAnonymousKey();

  if (!result) {
    console.warn('不支持的 SDK 版本。');
  } else if (result === 'INVALID_CATEGORY') {
    console.error('这是非游戏类别的 Mini App。');
  } else if (result === 'ERROR') {
    console.error('查询用户密钥时发生了错误。');
  } else if (result.type === 'HASH') {
    console.log('用户密钥：', result.hash);
    // 可以在这里使用用户密钥管理数据。
  }
}
```

{% endtab %}

{% tab title="React" %}

```tsx
import { getAnonymousKey } from '@apps-in-toss/web-framework';

function UserKeyButton() {
  async function handleClick() {
    const result = await getAnonymousKey();

    if (!result) {
      console.warn('不支持的 SDK 版本。');
      return;
    }

    if (result === 'INVALID_CATEGORY') {
      console.error('这是非游戏类别的 Mini App。');
      return;
    }

    if (result === 'ERROR') {
      console.error('查询用户密钥时发生了错误。');
      return;
    }

    if (result.type === 'HASH') {
      console.log('用户密钥：', result.hash);
      // 可以在这里使用用户密钥管理数据。
    }
  }

  return <button onClick={handleClick}>获取用户密钥</button>;
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { Button } from 'react-native';
import { getAnonymousKey } from '@apps-in-toss/framework';

function UserKeyButton() {
  async function handlePress() {
    const result = await getAnonymousKey();

    if (!result) {
      console.warn('不支持的 SDK 版本。');
      return;
    }

    if (result === 'INVALID_CATEGORY') {
      console.error('这是非游戏类别的 Mini App。');
      return;
    }

    if (result === 'ERROR') {
      console.error('查询用户密钥时发生了错误。');
      return;
    }

    if (result.type === 'HASH') {
      console.log('用户密钥：', result.hash);
      // 可以在这里使用用户密钥管理数据。
    }
  }

  return <Button onPress={handlePress} title="获取用户密钥" />;
}
```

{% endtab %}
{% endtabs %}

**参考事项**

* `getAnonymousKey`是非游戏 Mini App 专用的用户识别手段。
* Toss 登录(`appLogin`) 不同，它无需与服务器 API 联动也能使用。
* 建议以该用户密钥为基准管理用户数据。

***

### 验证识别密钥

用于验证用户识别密钥是否有效。

**基本信息**

| 项目           | 值                                  |
| ------------ | ---------------------------------- |
| Base URL     | `https://apps-in-toss-api.toss.im` |
| 服务器认证        | mTLS（客户端证书）                        |
| Content-Type | `application/json`                 |

{% hint style="info" %}
**服务器间通信需要 mTLS 证书**

识别密钥验证 API 是由合作方服务器调用 Apps in Toss 服务器的服务器间通信。为了安全，请先在服务器上配置 mTLS 证书后再调用。证书发放方法请参考 [mTLS 证书发放方法](https://developers-apps-in-toss.toss.im/documentation/integration/getting-started)。
{% endhint %}

* Method: `POST`
* Endpoint: `/api-partner/v1/apps-in-toss/users/anon-key/verify`

**请求头**

| 名称           | 类型     | 必填 | 说明                                                                                                             |
| ------------ | ------ | -- | -------------------------------------------------------------------------------------------------------------- |
| `x-anon-key` | string | Y  | [用户识别密钥发放](https://developers-apps-in-toss.toss.im/documentation/common/authentication/hash-key)中获得的 `hash` 值。 |

```bash
curl -X 'POST' \
  'https://apps-in-toss-api.toss.im/api-partner/v1/apps-in-toss/users/anon-key/verify' \
  -H 'accept: application/json' \
  -H 'x-anon-key: anon-key' \
  -d ''
```

**响应参数**

| 名称      | 类型     | 说明                                   |
| ------- | ------ | ------------------------------------ |
| success | string | 表示识别密钥是否有效。有效时返回 `"true"`，无效时返回错误响应。 |

```json
{
  "resultType": "SUCCESS",
  "success": "true"
}
```

**错误代码**

以下是使用 API 时可能发生的错误代码列表。请参考响应代码或消息， **并应用适当的异常处理逻辑**。

| 代码    | 消息                 |
| ----- | ------------------ |
| `401` | 没有用户识别密钥，或找不到映射的用户 |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/common/authentication/hash-key.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
