
# OAuth接入文档

欢迎使用 WEEX OAuth服务。本指南旨在帮助第三方平台（以下简称“平台方”）安全、高效地接入WEEX 用户授权系统。您的平台可以在获得用户授权后，获取用户特定的API 密钥，从而代替用户进行行情查询、现货及合约交易等操作。

## 流程概览

整个接入流程主要分为三个步骤：

1. 平台注册：联系 WEEX 商务注册您的平台信息，获取唯一的**clientId**和**secret**并配置回调地址等信息。
2. 用户授权：引导 WEEX 用户登录并授权，获取临时的授权码（code）。
3. 换取密钥：在后端使用 code 换取 `access_token`，再通过 `access_token` 获取最终的 API Key、Secret Key、Passphrase，用于后续的 API 调用。

## 接入准备

向WEEX提供以下信息完成平台注册：

| 配置项      | 说明                                                                           | 示例                                                                                        |
|----------|------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
| 平台名称     | 您的平台名称，将在用户授权页显示，只支持英文名称                                                     | MyTrading                                                                                 |
| WEEX UID | 平台方关联的 WEEX 用户ID，用于身份关联                                                      | 123456                                                                                    |
| 隐私条款     | 您的平台隐私条款地址                                                                   | https://www.mytrading.com/en/privacy-policy                                               |
| 服务条款     | 您的平台隐私条款地址                                                                   | https://www.mytrading.com/en/terms-of-use                                                 |
| 平台Logo   | 将显示在用户授权页的Logo图片                                                             |                                                                                           |
| 联系人      | 技术或商务联系人                                                                     |                                                                                           |
| 邮箱       | 联系人的邮箱地址                                                                     | tech@mytrading.com                                                                        |
| 电话       | 联系人的电话号码                                                                     |                                                                                           |
| 回调地址     | **关键配置**<br/>用户授权后，WEEX OAuth 服务器将重定向至此地址，并携带授权码。支持配置多个回调地址，但请求时必须完全匹配其中之一   | https://api.mytrading.com/oauth/callback<br/>https://sandbox.mytrading.com/oauth/callback |
| 出口 IP    | 为了确保通信安全，您需要提供平台服务器访问 WEEX 接口时的公网出口 IP 地址。WEEX 运维团队将为您配置白名单，未授权的 IP 将无法调用接口。 | 47.100.1.1, 47.100.1.2                                                                    |

## 接入步骤

### 1.拼接授权页面

```bash
# OAuth 授权页面示例
https://www.weex.com/oauth?
clientId={clientId}&
responseType=code&
scope=create:apikey&
redirectUri={redirectUri}&
state={state}&
codeChallenge={codeChallenge}&
codeChallengeMethod={codeChallengeMethod}
```
<strong>请求参数：</strong>

| 参数                  | 说明       | 备注                                                           |
|:--------------------|:---------|:-------------------------------------------------------------|
| clientId            | 商户身份标识   | 商户初始化完成后获得                                                   |
| responseType        | 响应类型     | 固定值：code                                                     |
| scope               | 权限范围     | 传 `create:apikey`                                            |
| state               | 状态参数     | 随机字符串，防 CSRF 攻击，22-128 位的 \[A-Z, a-z, 0-9, -, ., \_, ~]       |
| redirectUri         | 回调地址     | 必须在管理后台配置                                                    |
| codeChallenge       | PKCE 挑战值 | PKCE 挑战值，RFC 7636 规定格式：43-128 位的 [A-Z, a-z, 0-9, -, ., _, ~] |
| codeChallengeMethod | PKCE 方法  | PKCE 方法，当前仅支持 S256                                           |


**注：** 由于服务端强制PKCE，所以客户端需要生产pkce参数。

<strong>第一步：生成 Code Verifier (代码验证码)</strong>

客户端生成一个高熵的随机字符串 code_verifier。
- **要求**：由 [A-Z, a-z, 0-9, -, ., _, ~] 组成。
- **长度**：建议使用 43 位或以上（最大 128 位）。
  
<strong>第二步：生成 Code Challenge (代码挑战值)</strong>

对 code_verifier 进行 SHA256 哈希，然后进行 Base64URL 编码（且不得包含末尾的 = 填充符）。
`code_challenge = Base64URL(SHA256(code_verifier))`


### Java

```java
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.security.SecureRandom;

public class PKCEUtils {
    public static void main(String[] args) throws Exception {
        // 1. 生成 code_verifier (随机字符串)
        SecureRandom sr = new SecureRandom();
        byte[] codeValue = new byte[32];
        sr.nextBytes(codeValue);
        String codeVerifier = Base64.getUrlEncoder().withoutPadding().encodeToString(codeValue);

        // 2. 生成 code_challenge (S256)
        byte[] bytes = codeVerifier.getBytes(StandardCharsets.US_ASCII);
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        byte[] digest = messageDigest.digest(bytes);
        String codeChallenge = Base64.getUrlEncoder().withoutPadding().encodeToString(digest);

        System.out.println("code_verifier: " + codeVerifier);
        System.out.println("code_challenge: " + codeChallenge);
    }
}
```



----

### 2. 授权成功回调

用户完成授权后，页面将会301重定向至 redirectUri 回调地址

```bash
# 假设 redirect_uri = https://www.example.com/callback
# 回调后的 URL：
https://www.example.com/callback/?
code=sS38ddda0ddPC342342hhfuiu&
state=1234abc
```

----

### 3.获取 access_token

接口信息：

- URL: https://gateway.weex.com/v1/oauth/token
- 方法: POST
- 注：使用refresh_token刷新`access_token`成功后，原先的`access_token`会失效，即同一个refresh_token只会存在一个生效的`access_token`
- 签名：参考[签名规则](/zh-CN/products/broker/sign)


请求参数：

| 参数            | 类型     | 是否必须   | 参数描述                                           |
|:--------------|:-------|:-------|:-----------------------------------------------|
| grantType     | string | 是      | 授权类型，可选值：authorization_code、refresh_token      |
| code          | string | 否      | 返回的授权码，grantType=authorization_code 时需传        |
| redirectUri   | string | 否      | 回调地址，必须与授权时一致，grantType=authorization_code 时需传 |
| codeVerifier  | string | 否      | PKCE 原始值，grantType=authorization_code 时需传      |
| refresh_token | string | 否      | 刷新令牌，grantType=refresh_token 时需传               |

请求示例：

```powershell
curl -v -X POST {url} \
  -H 'Client-Id: weex123456' \
  -H 'Sign: *******' \
  -H 'Timestamp: 1735689600000' \
  -H 'Nonce: Nonce' \
  -d '{
  "grantType": "authorization_code",
  "code": "auth_code_xxx",
  "redirectUri": "https://api.wundertrading.com/oauth/callback",
  "codeVerifier": "code-verifier-demo"
  }'
```

返回参数：

| 参数               | 类型     | 参数描述                    |
|:-----------------|:-------|:------------------------|
| accessToken      | String | 访问令牌                    |
| refreshToken     | String | 刷新令牌                    |
| tokenType        | String | 令牌类型，固定为 Bearer         |
| expiresIn        | int    | access token 剩余有效期，单位秒  |
| refreshExpiresIn | int    | refresh token 剩余有效期，单位秒 |
| scope            | String | 授权范围                    |


返回示例：

```json
{
    "code": "00000",
    "msg": "success",
    "requestTime": 1774621008941,
    "data": {
        "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3NzU0MDkwNjQwIiwiYXVkIjoiY2FnZSIsInNjb3BlIjoiY3JlYXRlOmFwaWtleSIsImlzcyI6Imh0dHBzOi8vd2VleC5jb20iLCJleHAiOjE3NzQ2MjQ2MDgsImlhdCI6MTc3NDYyMTAwOCwianRpIjoiMzkifQ.mMVGvW0EeVO5TMxRiUDAyGmf64bcyEFXy0kz8xjv3wRp2pjsxpQUdT1Jn2V2SD0I6LhsCCRDp9Rhl6UuKnHYESBrqKWQONwf1nXTwIFB8Fmw_MqWFWVpi9nlaYBUIGiayuybllYZB1vN06fXRm5yq068UJFD_lSWMkrHJfUu5I7dD-JpwN9UNTsi5NY2a5vUc0WyBSPOnfnPBPr8x5PNB7uc9fr1Uew9QrmO2WnLuDCcDnZ2XGulzvmKC3b2ZXADDBKleuXAAgYzq-t-M4NBI2EjNP1wvpMGeTKyNTBKrXY4Wo0MQdipLGlKsr3cnpKdNqGWi9SzBSp-KctcGrpGew",
        "refreshToken": "o_3ubYfLM9zaqbwF_Xo9Jb13vyq-KPP6sVlGEAL3TjrBmbzao-xuT82VDVRFA-bCGuim2V-A_6vCbIiZsvdbjIefaGKaskNubXM9Wk3--7QwoSDqtpsUyD9KnJtoqToe",
        "tokenType": "Bearer",
        "expiresIn": 3600,
        "refreshExpiresIn": 36000,
        "scope": "create:apikey"
    }
}
```

----

### 4.获取Apikey

接口信息：

- URL: https://gateway.weex.com/v1/oauth/resource/create-api
- 方法: POST
- 認證: 需要在請求頭中攜帶 Authorization 信息
- 格式：`Bearer {access_token}`
- 示例：`Authorization: Bearer 12345`

注：
1. 同一个用户只能创建一个用户绑定三方的apikey，即只有用户不存在已绑定该三方的apikey时，接口才能调用成功。需重新绑定时，用户需要先删除原先已绑定的apikey。
2. 调用创建api key成功后，需要妥善保存apikey、secret、passphrase，只有在第一次调用成功后才会返回以上3个参数
3. 如果用户当前API状态不是**正常**，创建的APIKEY存在不能立马使用的情况。

请求示例：

```powershell
curl {url} \
  -H "Authorization: Bearer {access_token}"
```

返回示例：

```json
{
  "code": "00000",
  "data": {
    "apiKey": "ak_xxxxxxxxx",
    "secret": "sk_xxxxxxxxx",
    "passphrase": "pp_xxxxxxxxx"
  },
  "msg": "success",
  "requestTime": "1768529101682"
}
```


## 错误示例

```json
{
  "code": "80000",
  "msg": "param error",
  "requestTime": "1768529101682"
}
```
<strong>响应码列表</strong>

| 响应码   | 响应信息                                   | 响应描述                          |
|-------|----------------------------------------|-------------------------------|
| 00000 | success                                | 请求成功                          |
| 40400 | resource not found                     | 接口路径不存在或资源不存在                 |
| 80000 | param error                            | 请求参数错误                        |
| 80002 | client invalid                         | client 无效                     |
| 80003 | client auth failed                     | 客户端签名验证失败                     |
| 80004 | PKCE code_verifier verification failed | 客户端 PKCE 校验失败                 |
| 80005 | client mismatch                        | client 不匹配                    |
| 80006 | expired request                        | 请求已过期                         |
| 80007 | replay request                         | 重放请求                          |
| 80008 | uid duplicate                          | 该 uid 已绑定 client              |
| 80009 | client unauthorized                    | client 无权限                    |
| 80010 | user invalid                           | user 无效                       |
| 80100 | code invalid                           | 授权码无效                         |
| 80200 | redirect uri invalid                   | redirect uri 无效               |
| 80201 | redirect uri mismatch                  | redirect uri 不匹配              |
| 80300 | access token invalid                   | access token 无效               |
| 80301 | access token auth fail                 | access token 鉴权失败             |
| 80400 | refresh token invalid                  | refresh token 无效              |
| 80500 | grant type invalid                     | grant_type 无效                 |
| 80600 | scope invalid                          | scope 无效                      |
| 80601 | scope insufficient                     | scope 权限不足                    |
| 80700 | unsupported response type              | 不支持的 response type            |
| 80800 | state invalid                          | state 无效                      |
| 80900 | code challenge invalid                 | PKCE code_challenge 无效        |
| 80901 | code challenge method invalid          | PKCE code_challenge_method 无效 |
| 81000 | api key permission invalid             | API Key 权限无效                  |
| 81001 | api key already bound                  | API Key 已绑定                   |
| 81002 | user api key num exceeds max limit     | 用户 API Key 数量超过最大限制           |


## 安全与规范

### 保护密钥:
client_secret、code_verifier 以及最终获取的 secret_key 和 passphrase 都必须存储在后端，严禁放在前端代码或移动应用中。

### 验证 State:
严格验证回调中的 state 参数，防止 CSRF 攻击，建议使用随机字符串。

### 使用 HTTPS:
所有 API 请求必须通过 HTTPS 发起。
