> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qfex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 开发者集成指南

> 选择 OAuth 或钱包签名交易密钥接入用户，并将交易归因给您的 Builder Code

本指南面向交易所、DeFi 聚合器、交易终端、智能体以及其他希望让用户在 QFEX 交易并获得 Builder 奖励的应用。

## 选择身份认证流程

| 流程 | 集成获得的凭据 | 指南 |
| - | - | - |
| 钱包签名 Builder 注册 | 用于主账户交易、读取数据及向已登记地址提取加密资产的 API 密钥 | [Builder 钱包注册](https://docs.qfex.com/cn/api-reference/builder-wallet-registration.md) |
| OAuth 授权 | 用户的访问令牌及刷新令牌 | 参阅下文 OAuth 流程 |

钱包签名注册使用您现有、具备 `register_user` 权限的 Builder API 密钥。用户签署 QFEX 生成的消息后，QFEX 创建或恢复其钱包账户，然后返回交易密钥。此流程不需要 OAuth 客户端。

两种流程都需要在每条交易 WebSocket 连接上附加 Builder Code，才能归因奖励。

## OAuth 集成

OAuth 集成包含两个独立部分：

1. \*\*OAuth 识别并授权 QFEX 用户。\*\*每位终端用户登录 QFEX 并授权您的应用。新用户在 QFEX 上开户，不会向您的应用交出 QFEX 凭据。
2. \*\*Builder Code 标识您的集成。\*\*应用为这些用户打开已认证交易 WebSocket 会话时，附加同一个 Builder Code。

> [!NOTE]
>
> Builder Code **不会永久绑定到终端用户账户**，而是附加到交易 WebSocket 连接。在该连接存续期间，所有符合条件的订单都归因给该代码。

## 集成模型

典型聚合器拥有：

* 一个由聚合器拥有的 QFEX 账户；
* 该账户拥有的一个有效 Builder Code；
* 一个为聚合器应用登记的 QFEX OAuth 客户端；
* 每位连接账户的 QFEX 用户各自的一份 OAuth 授权及令牌组。

您**不需要**为每位交易者新建 Builder Code。

例如，某聚合器的代码为 `11111111-1111-4111-8111-111111111111`，则为 Alice、Bob 及其他通过聚合器交易的用户认证 QFEX 交易 WebSocket 时，均使用该代码。每位用户仍使用自己独立的 QFEX OAuth 访问令牌认证。

## 开始之前

### 1. 创建 Builder Code

登录 QFEX，在 \*\*Developer Settings → Builder code（开发者设置 → Builder Code）\*\*中创建，也可调用 `POST /user/builder-code`。

将返回的 UUID 保存为应用配置，例如：

```bash theme={null}
QFEX_BUILDER_CODE=11111111-1111-4111-8111-111111111111
```

Builder Code 是标识符，不是用户凭据。QFEX API 私密密钥和 OAuth 令牌属于敏感信息，必须单独存储。

手续费分成配置和代码生命周期操作见 [Builder Codes API](https://docs.qfex.com/cn/api-reference/builder-codes.md)。

### 2. 登记 OAuth 客户端

联系 [support@qfex.com](mailto:support@qfex.com)登记您的集成为 QFEX OAuth 客户端，并提供：

* 应用名称；
* 生产环境重定向 URI；
* 徽标 URL（如有）；
* 客户端是**公开型（public）**还是**机密型（confidential）**。

具有能够安全保存客户端密钥的后端时，使用**机密型**客户端。纯浏览器、移动及桌面应用必须使用**公开型**客户端，绝不能嵌入客户端密钥。

QFEX OAuth 使用带 PKCE 的 OAuth 2.1 授权码流程。

| 接口 | URL |
| - | - |
| 授权 | `https://verify.qfex.com/auth/v1/oauth/authorize` |
| 令牌 | `https://verify.qfex.com/auth/v1/oauth/token` |
| 交易 WebSocket | `wss://trade.qfex.com` |

> [!WARNING]
>
> QFEX OAuth 访问令牌是用户会话凭据，可以授权代表该用户交易。访问令牌和刷新令牌必须按秘密信息保护。不要记录到日志或分析事件中，也不要向浏览器暴露机密型客户端的令牌。

## 终端用户流程

### 第 1 步：用户选择连接 QFEX

用户在您的应用中选择 \*\*Connect QFEX（连接 QFEX）\*\*时：

1. 生成高熵的 `state` 值。
2. 生成 PKCE `code_verifier`。
3. 根据验证字符串计算 SHA-256 `code_challenge`。
4. 在用户服务端会话或其他安全短期存储中保存 `state` 与 `code_verifier`。
5. 将用户重定向到 QFEX 授权接口。

Node.js 示例：

```javascript theme={null}
import crypto from "node:crypto";

const QFEX_AUTHORIZE_URL = "https://verify.qfex.com/auth/v1/oauth/authorize";

function randomBase64Url(bytes = 32) {
  return crypto.randomBytes(bytes).toString("base64url");
}

function createPkceChallenge(verifier) {
  return crypto.createHash("sha256").update(verifier).digest("base64url");
}

const state = randomBase64Url();
const codeVerifier = randomBase64Url(48);
const codeChallenge = createPkceChallenge(codeVerifier);

// Persist these against the user's login/session until the callback completes.
session.qfexOAuth = { state, codeVerifier };

const url = new URL(QFEX_AUTHORIZE_URL);
url.searchParams.set("response_type", "code");
url.searchParams.set("client_id", process.env.QFEX_OAUTH_CLIENT_ID);
url.searchParams.set("redirect_uri", "https://aggregator.example.com/oauth/qfex/callback");
url.searchParams.set("scope", "openid email profile");
url.searchParams.set("state", state);
url.searchParams.set("code_challenge", codeChallenge);
url.searchParams.set("code_challenge_method", "S256");

response.redirect(url.toString());
```

绝不能省略 `state` 或 PKCE。

### 第 2 步：QFEX 处理登录或开户

用户被送往 QFEX，而不是您应用内的凭据表单。

* 已有 QFEX 账户的用户登录并完成所需 MFA。
* 没有账户的用户在 QFEX 开户，并完成必要准入步骤。
* 用户查看 OAuth 授权请求，并选择批准或拒绝您的应用。

您的应用**不应**收集用户的 QFEX 密码、MFA 验证码、API 私密密钥或服务角色凭据，也不应直接通过底层认证服务创建用户。将开户保留在 QFEX，可确保账户验证、条款、资格及准入由 QFEX 控制。

> [!WARNING]
>
> 当前预发布流程中，全新账户注册及准入后的 OAuth 连续跳转仍在完善。现有 QFEX 用户可完成端到端 OAuth 流程。新建账户的用户可能需要先完成准入，返回您的应用，再次选择 **Connect QFEX（连接 QFEX）**。计划在开发者集成全面开放前移除这一额外步骤。

### 第 3 步：处理 OAuth 回调

用户批准后，QFEX 将其重定向至已登记的 `redirect_uri`，并携带授权 `code` 及原始 `state`。

```text theme={null}
https://aggregator.example.com/oauth/qfex/callback?code=...&state=...
```

在回调接口中：

1. 若 `state` 与用户会话中保存的值不完全一致，拒绝请求。
2. 读取已保存的 PKCE `code_verifier`。
3. 用授权码交换令牌。
4. 从会话删除一次性的 `state` 和 `code_verifier`。

### 第 4 步：用授权码交换 QFEX 令牌

对于机密型服务端客户端，使用 HTTP Basic 认证客户端，并发送 PKCE 验证字符串：

```bash theme={null}
curl -X POST 'https://verify.qfex.com/auth/v1/oauth/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -u "$QFEX_OAUTH_CLIENT_ID:$QFEX_OAUTH_CLIENT_SECRET" \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'code=AUTHORIZATION_CODE' \
  --data-urlencode 'redirect_uri=https://aggregator.example.com/oauth/qfex/callback' \
  --data-urlencode 'code_verifier=PKCE_CODE_VERIFIER'
```

成功响应包含访问令牌和刷新令牌。将两者与已连接用户关联并安全保存。

公开型客户端不发送客户端密钥，而是在表单体中提供 `client_id`，但仍须使用 PKCE。

### 第 5 步：打开交易 WebSocket 并附加 Builder Code

将用户的 OAuth `access_token` 用作 JWT。WebSocket 升级请求和 QFEX 认证消息均使用用户令牌，Builder Code 添加在认证消息中。

```javascript theme={null}
import WebSocket from "ws";

const accessToken = user.qfexAccessToken;
const builderCode = process.env.QFEX_BUILDER_CODE;

const ws = new WebSocket(
  `wss://trade.qfex.com/?jwt=${encodeURIComponent(accessToken)}`,
);

ws.on("open", () => {
  ws.send(
    JSON.stringify({
      type: "auth",
      params: {
        jwt: accessToken,
        builder_code: builderCode,
      },
    }),
  );
});
```

若用户选择了子账户，在同一认证消息中包含其 ID：

```json theme={null}
{
  "type": "auth",
  "params": {
    "jwt": "USER_OAUTH_ACCESS_TOKEN",
    "account_id": "22222222-2222-4222-8222-222222222222",
    "builder_code": "11111111-1111-4111-8111-111111111111"
  }
}
```

Builder Code 随后固定在该 WebSocket 连接的整个生命周期内，不要在每个订单中重复添加。

### 第 6 步：正常交易

认证响应成功后，通过普通交易 WebSocket API 下单。

```json theme={null}
{ "type": "auth", "result": "success" }
```

该归因连接提交的普通订单、触发单和 TWAP 订单自动继承 Builder Code。奖励记入拥有该代码的 QFEX 账户。

OAuth 不会绕过 QFEX 账户要求。若账户仍需身份验证、接受更新条款或其他准入步骤，在用户于 QFEX 完成这些步骤之前，交易可能被拒绝。

另见：

* [身份认证](https://docs.qfex.com/cn/websocket/channels/trade/authenticate.md)
* [提交订单](https://docs.qfex.com/cn/websocket/channels/trade/add_order.md)
* [Builder Codes API](https://docs.qfex.com/cn/api-reference/builder-codes.md)

### 第 7 步：刷新令牌并重连

OAuth 访问令牌会过期。请在过期前或认证失败后，使用刷新令牌获取新访问令牌。

机密型客户端示例：

```bash theme={null}
curl -X POST 'https://verify.qfex.com/auth/v1/oauth/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -u "$QFEX_OAUTH_CLIENT_ID:$QFEX_OAUTH_CLIENT_SECRET" \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'refresh_token=USER_REFRESH_TOKEN'
```

使用刷新后的访问令牌创建新的交易 WebSocket 时，在新的认证消息中再次附加 Builder Code。

若用户在 QFEX 中撤销对应用的授权，请停止替该用户交易；只有用户选择重新连接时，才重新进行 OAuth 流程。

## 新用户与现有用户使用同一入口

集成应提供一个 \*\*Connect QFEX（连接 QFEX）\*\*操作，不要在您这一侧构建独立的“注册”和“登录”API。

| 用户状态 | 行为 |
| - | - |
| 没有 QFEX 账户 | QFEX 处理开户及准入。预发布期间，用户可能需返回您的应用并再次选择连接 QFEX 才能完成 OAuth。 |
| 已有 QFEX 账户 | QFEX 在必要时要求登录，再授权您的应用。 |
| 已登录 QFEX | 可直接进入授权界面。 |
| 已存在有效授权 | QFEX 可能无需再次输入凭据即可完成授权流程。 |
| 授权被撤销或刷新令牌无效 | 启动新的授权码流程。 |

## Builder 归因以连接为范围

Builder 归因刻意独立于开户及 OAuth。这意味着：

* 终端用户账户不会永久绑定某个开发者；
* 同一用户可以在不同时候通过不同开发者交易；
* 用户直接在 QFEX 交易时，不会自动归因给您；
* 您的集成打开的每条交易 WebSocket 都必须包含 `builder_code`；
* 不附加代码重连时，新连接不再具有 Builder 归因。

因此，应从受信任的应用配置设置 `builder_code`，而不是接受浏览器或终端用户提供的任意值。

## 安全检查清单

上线前：

* 所有 OAuth 流程均使用授权码加 PKCE；
* 每次回调均校验 `state`；
* 登记精确的 HTTPS 重定向 URI，不使用通配符回调；
* 将机密型客户端密钥、访问令牌和刷新令牌留在服务端；
* 加密保存刷新令牌；
* 不记录访问令牌、刷新令牌、授权码或 QFEX API 私密密钥；
* 不在您的应用内索取用户 QFEX 密码或 MFA 验证码；
* 刷新后使用新访问令牌重连交易 WebSocket；
* 每条新交易 WebSocket 均附加配置的 Builder Code；
* 授权撤销后立即停止交易。

> [!NOTE]
>
> 标准 OAuth scope 描述认证服务返回的身份信息，不应视为 QFEX 交易中“只读”或“仅交易”的权限边界。用于 QFEX 交易 API 的访问令牌，必须作为能够代表用户操作的凭据保护。

## 端到端检查清单

能够测试以下全部项目，才算完成生产集成：

1. 无 QFEX 账户的用户可从连接 QFEX 进入开户流程；新用户 OAuth 连续跳转功能发布后，能够在准入完成后返回原授权请求。
2. 现有用户无需向您的应用分享凭据即可连接。
3. 回调拒绝无效 `state` 或 PKCE 验证字符串。
4. 可以交换授权码，并安全保存返回的令牌组。
5. 可以用用户访问令牌认证 `wss://trade.qfex.com`。
6. 交易 WebSocket 认证消息自动包含您的 Builder UUID。
7. 通过该连接提交的普通订单、触发单及 TWAP 均归因给您。
8. 刷新令牌并重连 WebSocket 后，归因保持正确。
9. 撤销已连接应用后，无法继续使用被撤销的授权。

需要为集成登记 OAuth 客户端时，请联系 [support@qfex.com](mailto:support@qfex.com)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.