> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/auth-tokens.md).

# 使用认证令牌连接

通过在服务器端签发 auth token，并在浏览器中使用该 token 连接 Web SDK，从而将 Convai API 密钥保留在你的服务器上。

使用由你的服务器签发的 auth token 连接 Convai Web SDK，这样你的 API key 就永远不会到达浏览器。在发布任何与角色交互的页面之前，请先使用此页面。

### 为什么使用 auth token

API key 是你整个 Convai 账户的凭据。客户端包中的任何内容，任何打开页面的人都可以读取，因此随应用一起发布的 API key 可能被复制并在你的应用之外使用。auth token 由你的服务器基于 API key 创建，并且只会将该 token 发送到浏览器。

```mermaid
sequenceDiagram
    participant Browser
    participant Server as 你的服务器
    participant Convai
    Browser->>Server: 请求一个 token
    Server->>Convai: 使用 CONVAI-API-KEY 发送 POST /user/connect
    Convai-->>Server: apiAuthToken
    Server-->>Browser: Token
    Browser->>Convai: 使用 authToken 调用 connect()
```

该图显示 API key 保留在你的服务器上：浏览器只会持有 token。

### 在你的服务器上签发 token

发送一个 `POST` 请求到 `https://api.convai.com/user/connect` 并在你的 API key 作为 `CONVAI-API-KEY` 请求头中发送它。token 位于 `apiAuthToken` JSON 响应的字段中。

{% tabs %}
{% tab title="Node.js" %}
{% code title="server/token.ts" %}

```typescript
export async function createConvaiToken(): Promise<string> {
  const response = await fetch('https://api.convai.com/user/connect', {
    method: 'POST',
    headers: {
      'CONVAI-API-KEY': process.env.CONVAI_API_KEY!,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({}),
  });
  if (!response.ok) {
    throw new Error(`Token request failed: ${response.status}`);
  }
  const data = await response.json();
  return data.apiAuthToken;
}
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}

```python
import os
import requests

def create_convai_token() -> str:
    response = requests.post(
        "https://api.convai.com/user/connect",
        headers={
            "CONVAI-API-KEY": os.environ["CONVAI_API_KEY"],
            "Content-Type": "application/json",
        },
        json={},
    )
    response.raise_for_status()
    return response.json()["apiAuthToken"]
```

{% endtab %}
{% endtabs %}

通过你自己的端点公开该函数，并且只有已登录的终端用户才能调用。

### 使用 token 连接

传入 `authToken` 而不是 `apiKey`。其他所有选项保持不变。

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

```tsx
import { useConvaiClient } from '@convai/web-sdk/react';
import { ConvaiWidget } from '@convai/web-widget/react';

export function Assistant({ token }: { token: string }) {
  const client = useConvaiClient({
    authToken: token,
    characterId: 'YOUR_CHARACTER_ID',
  });

  return <ConvaiWidget convaiClient={client} />;
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
import { ConvaiClient } from '@convai/web-sdk/core';

const token = await fetch('/api/convai-token').then((r) => r.text());

const client = new ConvaiClient({
  authToken: token,
  characterId: 'YOUR_CHARACTER_ID',
});

await client.connect();
```

{% endtab %}
{% endtabs %}

原生 `createConvaiWidget()` 辅助函数也接受 `authToken` 替代 `apiKey` 当你让它创建客户端时。

中的凭据规则 `connect()`:

| 配置                        | 结果                                                              |
| ------------------------- | --------------------------------------------------------------- |
| `authToken` 设置            | SDK 会在 `API-AUTH-TOKEN` 请求头中发送它。当……也被设置时，它优先级更高。 `apiKey` 也被设置。 |
| 仅 `apiKey` 设置             | SDK 会在 `X-API-Key` 请求头。                                         |
| 两者都未设置，或者没有 `characterId` | `connect()` 会抛出 `需要 apiKey 或 authToken 之一，且 characterId 是必需的`.  |

为该会话创建的长期记忆管理器使用相同的凭据，因此记忆调用也可以使用 token。请参阅 [使用长期记忆](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/long-term-memory.md).

{% hint style="danger" %}
不要在面向公众的页面的浏览器代码中发布 API key。保留 `apiKey` 用于本地开发和服务端工具。
{% endhint %}

### 验证连接

从页面连接并确认 `connect()` 已解析，并且 `botReady` 事件触发。在浏览器的网络面板中， `/connect` 请求携带一个 `API-AUTH-TOKEN` 请求头，并且没有 `X-API-Key` 请求头。

### 后续步骤

{% content-ref url="/pages/1ef8009eea712d4c41fd7a2a07e473a277395698" %}
[处理错误和断开连接](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/error-handling.md)
{% endcontent-ref %}

{% content-ref url="/pages/4f33318cc644cad5dc970e09e48c72b8b29329f6" %}
[使用长期记忆](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/long-term-memory.md)
{% endcontent-ref %}

{% content-ref url="/pages/dff296725774f9173a7391e28344f5f94cf35b60" %}
[配置和类型参考](/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/vanilla-typescript/best-practices-and-type-definitions.md)
{% endcontent-ref %}


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/web-plugins/convai-web-sdk/auth-tokens.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
