> For the complete documentation index, see [llms.txt](https://docs.jgopay.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.jgopay.com/jian-ti-zhong-wen/authentication.md).

# 身份认证

所有 API 请求采用两步认证：先用商户凭据换取短期有效的访问令牌（access token），再用该令牌调用 API。

## 第一步：获取访问令牌

```http
POST /auth/token
Authorization: Basic base64(merchant_id:api_key)
Content-Type: application/json
```

### 示例

```bash
# 编码凭据：base64("MRC_MYR_001:your_api_key")
curl -X POST https://api.pays3bucket.com/api/v1/auth/token \
  -H "Authorization: Basic TVJDX01ZUl8wMDE6eW91cl9hcGlfa2V5" \
  -H "Content-Type: application/json"
```

### 响应

```json
{
  "status": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 3600
  }
}
```

| 字段             | 类型     | 说明                |
| -------------- | ------ | ----------------- |
| `access_token` | string | 用于调用 API 的 JWT 令牌 |
| `token_type`   | string | 固定为 `Bearer`      |
| `expires_in`   | number | 令牌有效期，单位秒（3600）   |

## 第二步：使用令牌

在后续所有请求的 `Authorization` 头中携带令牌：

```http
Authorization: Bearer <access_token>
Content-Type: application/json
```

## 重要说明

* 访问令牌 **1 小时**（3600 秒）后过期
* 请在当前令牌过期前申请新令牌
* 切勿在客户端代码中暴露 `merchant_id` 或 `api_key`
* 每次换取令牌都会创建一个新会话

## API 密钥管理

### 密钥轮换

轮换 API 密钥的步骤：

1. 联系您的客户经理申请密钥轮换
2. 生成新密钥后，**旧密钥立即失效**
3. 用旧密钥换取的、仍在有效期内的访问令牌可继续使用（最长 1 小时）
4. 请在最后一个有效令牌过期前，将集成更新为新密钥

> **重要：** 请在申请轮换前准备好新密钥的部署方案。没有过渡期 — 旧密钥会立即停止工作。

### 何时轮换

| 触发条件        | 处理措施          |
| ----------- | ------------- |
| 怀疑密钥泄露      | 立即轮换 + 审查访问日志 |
| 团队成员离职      | 24 小时内轮换      |
| 密钥出现在日志或代码中 | 立即轮换          |
| 例行维护        | 建议每 90 天轮换一次  |

### 紧急吊销

如果您的 API 密钥已泄露：

1. 立即联系客户经理进行紧急吊销
2. 密钥被停用后，所有新的令牌换取请求都会被拒绝
3. 已签发的令牌在过期前仍然有效（最长 1 小时）
4. 签发新密钥并部署后方可恢复服务

### 密钥存储

* 将 API 密钥保存在**环境变量**或**密钥管理服务**中（如 AWS Secrets Manager、HashiCorp Vault）
* **切勿**将密钥硬编码在源代码中
* **切勿**将密钥提交到版本控制系统（即使是私有仓库）
* **切勿**将密钥打包进客户端代码、移动应用或浏览器代码
* 仅授权确实需要密钥的服务访问

## 令牌存储

### 服务端集成（推荐）

将访问令牌保存在**内存**（进程变量）中即可。令牌有效期短（1 小时）且重新获取成本低，无需持久化。

```javascript
let accessToken = null;
let tokenExpiresAt = 0;

async function getToken() {
  if (accessToken && Date.now() < tokenExpiresAt - 60000) {
    return accessToken; // 距离过期超过 1 分钟时复用
  }
  const response = await exchangeCredentials();
  accessToken = response.data.access_token;
  tokenExpiresAt = Date.now() + response.data.expires_in * 1000;
  return accessToken;
}
```

### 浏览器端集成

如果您的架构需要浏览器直接与 API 通信：

* **切勿**将令牌存入 `localStorage` 或 `sessionStorage` — 页面上任何 JavaScript（包括 XSS 注入的脚本）都能读取
* 使用由您的后端服务器设置的 **HttpOnly**、**Secure**、**SameSite=Strict** Cookie
* 让您的后端充当代理：浏览器与您的服务器通信，您的服务器与 JGoPay 通信
* 如必须在浏览器内存中持有令牌，切勿持久化，并在页面卸载时清除

### 禁止的做法

| 做法                   | 风险               |
| -------------------- | ---------------- |
| 将令牌存入 `localStorage` | XSS 攻击可读取令牌并创建支付 |
| 在前端代码中内嵌 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.jgopay.com/jian-ti-zhong-wen/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.
