> For the complete documentation index, see [llms.txt](https://docs.nexus.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexus.xyz/api-reference/zh-cn/guides/authentication.md).

# 身份验证

EVM 钱包登录与 API 密钥管理，共四个操作。

这里涉及两种凭证，它们不能互换：

1. **会话令牌**。您用 EVM 钱包对一条固定消息签名（EIP-191 `personal_sign`）即可获得。它是一个 `Bearer` 令牌，有效期为**24小时**，**仅**用于 `/keys` 端点的身份验证。您不能用它进行交易。
2. **API 密钥**。用会话令牌创建的一对 `key_id` + `secret`。您使用 HMAC-SHA256，以该 secret 对每个交易和账户请求签名。secret 仅在创建时返回**一次**，之后不会存储，也不会再次显示。

```
POST /auth/login   (wallet signature)         → session Bearer token
POST /keys         (Bearer)                    → key_id + secret
sign each request  (HMAC over canonical str)   → trade
```

如需避免暴露主钱包的委派签名方式，请参见[代理](/api-reference/zh-cn/guides/agent-keys.md)。

以下所有示例的基础 URL：`https://api.testnet.nexus.xyz/v1`，即公共测试网基础 URL。

***

## `POST /auth/login`

使用 EVM 钱包登录。

提交一个 EIP-191 `personal_sign` 签名以获取会话令牌。使用会话令牌通过 `/keys` 端点创建和管理 API 密钥。交易请改用 HMAC API 密钥。会话令牌在24小时后过期。

**身份验证**：无。请求通过其携带的钱包签名自行完成身份验证。

### 请求体

`LoginRequest`，`application/json`，必填。

| 字段          | 类型     | 必填 | 说明                                        |
| ----------- | ------ | -- | ----------------------------------------- |
| `message`   | string | 是  | 必须完全等于：`Sign in to Nexus Exchange`        |
| `signature` | string | 是  | EIP-191 `personal_sign` 十六进制值（0x 前缀，65字节） |

该消息是一个固定字符串，而不是 nonce 质询，也没有单独的“请求质询”调用。服务器会从签名中*恢复*出您的钱包地址，因此您无需发送地址。

### 响应

#### `200`

会话已创建。`LoginResponse`。

| 字段        | 类型     | 说明                                           |
| --------- | ------ | -------------------------------------------- |
| `token`   | string | 会话令牌（64字符十六进制）。作为 `/keys` 端点的 `Bearer` 令牌使用。 |
| `address` | string | 恢复出的以太坊地址（0x 前缀）                             |

#### `401`

签名验证失败。

### 示例

```bash
curl -X POST 'https://api.testnet.nexus.xyz/v1/auth/login' \
  -H 'Content-Type: application/json' \
  -d '{
    "message": "Sign in to Nexus Exchange",
    "signature": "0x1234...abcd"
  }'
```

响应：

```json
{
  "token": "a1b2c3d4e5f6...",
  "address": "0xAbCdEf0123456789..."
}
```

***

## `POST /keys`

创建 API 密钥。

为已认证的钱包创建一个新的 HMAC API 密钥。secret 只返回一次，之后不会存储，也不会再次显示。需要来自 `POST /auth/login` 的会话令牌（Bearer）。

**身份验证**：`bearerAuth`（会话令牌）。

### 请求体

可选。[`CreateKeyRequest`](https://docs.nexus.xyz/api-reference/guides/schemas#createkeyrequest)。请求体缺失或为空等同于 `{}`。

| 字段       | 类型      | 说明                                                                                  |
| -------- | ------- | ----------------------------------------------------------------------------------- |
| `label`  | string  | 调用方为该密钥提供的标签，会在 `GET /keys` 中原样返回。                                                  |
| `ttl_ms` | integer | 密钥的有效时长，从创建时起算，单位为毫秒。省略则密钥永不过期。必须在 `[24h, 90d]`（86400000–7776000000毫秒）范围内，否则请求会被拒绝。 |

### 响应

#### `200`

密钥已创建。[`CreateKeyResponse`](https://docs.nexus.xyz/api-reference/guides/schemas#createkeyresponse)。

| 字段              | 类型              | 说明                                                                                                                                                        |
| --------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `key_id`        | string          | 密钥标识符。在已签名请求中作为 `X-API-Key` 发送。                                                                                                                           |
| `secret`        | string          | HMAC secret，十六进制。**仅返回一次**。请立即保存。无法找回。                                                                                                                    |
| `expires_at_ms` | integer or null | 该密钥停止通过身份验证的时间点，Unix 毫秒；若永不过期则为 `null`。这是 `ttl_ms` 解析后的值。**可为 null，但不是可选字段**：始终存在。目前只有基于 Postgres 的部署会执行该限制。在非 Postgres 部署上创建的密钥接受 `ttl_ms`，但尚不会拒绝已过期的密钥。 |

#### `400`

错误请求：

| `code`             | 含义                                                       |
| ------------------ | -------------------------------------------------------- |
| `ttl_ms_invalid`   | 提供了 `ttl_ms`，但它不是非负整数；或者请求体本身无法读取（超过8KB 限制，或不是有效的 JSON）。 |
| `ttl_out_of_range` | 格式正确的 `ttl_ms` 超出了 `[24h, 90d]` 范围。                      |

#### `401`

需要有效的会话令牌。

### 示例

```bash
curl -X POST 'https://api.testnet.nexus.xyz/v1/keys' \
  -H 'Authorization: Bearer a1b2c3d4e5f6...' \
  -H 'Content-Type: application/json' \
  -d '{"label": "my trading bot", "ttl_ms": 2592000000}'
```

响应：

```json
{
  "key_id": "nx_a1b2c3d4e5f67890",
  "secret": "deadbeef...",
  "expires_at_ms": 1735689600000
}
```

新密钥默认获得 **Pro** 等级。运营方通过 [`PUT /admin/tiers`](https://docs.nexus.xyz/api-reference/admin/set-tier) 分配等级，每个响应都会在 `X-RateLimit-*` 响应头中报告各等级的上限。

***

## `GET /keys`

列出您的 API 密钥。

返回已认证钱包拥有的所有密钥的密钥 ID 和等级。不包含 secret。

**身份验证**：`bearerAuth`（会话令牌）。

### 响应

#### `200`

该会话的 API 密钥。一个裸数组。契约提供了示例，但没有命名的 Schema。

| 字段       | 类型     | 说明                                    |
| -------- | ------ | ------------------------------------- |
| `key_id` | string | 密钥标识符                                 |
| `tier`   | string | 分配给该密钥的速率限制等级，例如 `Pro`、`Market Maker` |

#### `401`

需要有效的会话令牌。

### 示例

```bash
curl 'https://api.testnet.nexus.xyz/v1/keys' \
  -H 'Authorization: Bearer a1b2c3d4e5f6...'
```

响应：

```json
[
  {
    "key_id": "nx_a1b2c3d4e5f67890",
    "tier": "Pro"
  }
]
```

***

## `DELETE /keys/{key_id}`

删除 API 密钥。

删除您拥有的密钥。不能删除其他钱包拥有的密钥。

**身份验证**：`bearerAuth`（会话令牌）。

### 参数

| 名称       | 位置   | 类型     | 必填 | 说明        |
| -------- | ---- | ------ | -- | --------- |
| `key_id` | path | string | 是  | 要删除的密钥标识符 |

### 响应

#### `200`

密钥已删除。

#### `401`

需要有效的会话令牌。

#### `404`

未找到密钥，或该密钥不归您所有。所有权校验失败返回 `404` 而非 `403`，因此您无法借此探查其他钱包的密钥 ID。

### 示例

```bash
curl -X DELETE 'https://api.testnet.nexus.xyz/v1/keys/nx_a1b2c3d4e5f67890' \
  -H 'Authorization: Bearer a1b2c3d4e5f6...'
```

***

## 使用密钥对请求签名

拿到 `key_id` 和 `secret` 后，每个 `hmacAuth` 操作都需要三个请求头：

| 请求头           | 值                                     |
| ------------- | ------------------------------------- |
| `X-API-Key`   | 您的密钥 ID，例如 `nx_a1b2c3d4e5f67890`      |
| `X-Timestamp` | 当前时间，Unix **毫秒**                      |
| `X-Signature` | `hex(hmac_sha256(secret, canonical))` |

规范字符串由五个以换行符分隔的字段组成：

```
<timestamp>\n<METHOD>\n<path>\n<query>\n<sha256_hex(body)>
```

* `path` 是**契约中写明的**路径，*而不是*您所调用的完整 URL 路径。`/v1` 传输前缀会在请求到达验证签名的服务之前被去除，因此**不得**对其签名。调用带版本的路径时，请包含 `/api/v1` 前缀，因为这一部分会被转发。

  | 您调用的                                           | 您签名的              |
  | ---------------------------------------------- | ----------------- |
  | `https://api.testnet.nexus.xyz/v1/markets`     | `/markets`        |
  | `https://api.testnet.nexus.xyz/api/v1/tickers` | `/api/v1/tickers` |

  对 `/v1` 传输前缀签名是导致不透明 `401` 的第二常见原因，仅次于时钟偏差。
* `query` 是原始查询字符串，没有时为空。
* 对于没有请求体的请求，对空字符串做哈希。
* 时间戳必须与服务器时间相差不超过**30秒**。时钟偏差是导致不透明 `401` 的最常见原因。

建议性的 `X-Nexus-Api-Version` 和 `User-Agent` 请求头**不**计入规范字符串。

```bash
TIMESTAMP=$(python3 -c 'import time; print(int(time.time()*1000))')
BODY_HASH=$(printf '' | shasum -a 256 | cut -d' ' -f1)
CANONICAL="$TIMESTAMP\nGET\n/markets\n\n$BODY_HASH"
SIGNATURE=$(printf '%s' "$CANONICAL" | openssl dgst -sha256 -mac HMAC \
  -macopt "hexkey:$NEXUS_API_SECRET" -hex | awk '{print $NF}')

curl 'https://api.testnet.nexus.xyz/v1/markets' \
  -H "X-API-Key: nx_a1b2c3d4e5f67890" \
  -H "X-Timestamp: $TIMESTAMP" \
  -H "X-Signature: $SIGNATURE"
```

所有 `401` 响应都返回同样不透明的响应体 `{"code":"unauthorized"}`，因此响应不会告诉您问题出在密钥、签名还是时钟。请先检查时钟偏差，然后检查规范字符串，最后检查密钥。

> **状态**：测试网预览版。凭证、会话和速率限制状态目前还无法在网关重启后保留，因此请将 API 密钥视为可重新创建的。


---

# 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://docs.nexus.xyz/api-reference/zh-cn/guides/authentication.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.
