# 使用统一认证登录你的应用 · API 参考

本文面向：**把统一认证当作 OAuth 2.0 授权服务器**、在自有产品中接授权码流程的第三方应用。根地址记为 `{{BASE_URL}}`（生产环境请换成实际域名，无尾斜杠）。

**接入步骤与概念**见 [接入指引](./idp-oauth2-integration.md)。

**可选机器可读规范**（仅路径子集，无交互文档）：[openapi-idp-oauth2.yaml](/openapi-idp-oauth2.yaml)（由 `npm run openapi:build` 生成）。

---

## 通用约定

- **成功**：JSON 多为 `{ "data": …, "message"?: string }`（OAuth 换票成功见下文，为扁平字段）。
- **错误**：JSON `{ "error": { "code": string, "message": string, "details"?: object } }`。
- **用户会话**：授权页浏览器侧使用 Cookie `auth_token`；换票后你的**服务端**使用 `Authorization: Bearer <access_token>` 调用户信息接口。

---

## GET {{BASE_URL}}/api/oauth/authorize

浏览器打开授权页。未登录会进登录流；已登录且未同意会进同意页。

**查询参数**

| 参数 | 必填 | 说明 |
|------|------|------|
| `client_id` | 是 | 登记应用时获得的 Client ID |
| `redirect_uri` | 是 | 必须与登记回调之一完全一致 |
| `response_type` | 是 | 固定 `code` |
| `scope` | 否 | 如 `openid profile email` |
| `state` | 否 | 原样带回你的应用，防 CSRF |
| `code_challenge` | 否 | PKCE |
| `code_challenge_method` | 否 | 与 `code_challenge` 配套 |

**响应**：`302` 重定向到登录页、同意页或错误说明页（具体以线上行为为准）。

---

## GET {{BASE_URL}}/api/oauth/authorize/confirm

用户在同意页确认授权后由站内跳转调用；**需**已登录（Cookie `auth_token` 或 Bearer 会话）。

查询参数与 `/api/oauth/authorize` 相同（`client_id`、`redirect_uri`、`response_type=code` 等）。

**响应**

- `302`：重定向到你的 `redirect_uri`，并附带 `code`（及可选 `state`）。
- `400` / `401`：JSON 错误体。

---

## GET {{BASE_URL}}/api/oauth/authorize/cancel

用户取消授权时由授权流程跳转至此。

**查询参数**：`client_id`、`redirect_uri` 必填；`state` 可选。

**响应**：`303` 或 `302` 重定向回你的应用（携带取消或错误相关查询参数，以实现为准）。

---

## POST {{BASE_URL}}/api/oauth/token

**服务端**用授权码换访问令牌。`Content-Type: application/x-www-form-urlencoded`。

**表单字段**

| 字段 | 必填 | 说明 |
|------|------|------|
| `grant_type` | 是 | `authorization_code` |
| `code` | 是 | 授权码（一次性） |
| `client_id` | 是 | Client ID |
| `redirect_uri` | 是 | 与授权请求中一致 |
| `client_secret` | 条件 | 非公开客户端必填 |
| `code_verifier` | 条件 | 使用 PKCE 时必填 |

**成功 `200`**：`application/json`，扁平结构，例如：

- `access_token`、`token_type`、`expires_in`、`scope`

**错误**：`400`、`401` 等为 JSON 错误体。

---

## GET {{BASE_URL}}/api/auth/me

用换票得到的 **Bearer** 访问令牌读取当前授权用户资料。

**请求头**：`Authorization: Bearer <access_token>`

**成功 `200`**：`{ "data": { … } }`，`data` 内含用户 id、邮箱、昵称、头像、验证状态等字段（以实际响应为准）。

**错误**：`401` 等。

---

## 托管补绑邮箱（浏览器侧，带站内会话）

当流程要求用户在统一认证站补绑邮箱时，由**站内页面**调用；你的独立业务应用后端通常不需要对接。

### POST {{BASE_URL}}/api/oauth/email/send

**请求体** `application/json`：`{ "email": "<用户邮箱>" }`

**响应**：`200` 表示已触发发送；`400` / `401` / `403` / `429` / `500` 等为错误。

### POST {{BASE_URL}}/api/oauth/email/verify

**请求体** `application/json`：

- `code`（必填）：邮件中的验证码
- `deviceFingerprint`（可选，字符串，长度上限以服务端为准）

**成功 `200`**：绑定成功，可能下发 `Set-Cookie` 更新会话。

**错误**：`400` / `401` / `429` 等。

---

## 与「接上游 GitHub/Google」文档的区别

本文路径服务于 **RP（你的应用）接统一认证当 IdP**。  
在统一认证**本站**登录页接 GitHub/Google 的配置与回调，见 [接上游 IdP · 配置说明](./upstream-idp-integration.md) 与 [接上游 · API 参考](./upstream-idp-api.md)；二者都在 `/api/oauth/` 下但语义不同，请勿混用。
