跳转至

认证 API

所有认证接口位于 /auth 路径前缀下,负责用户注册、登录、OAuth、会话管理和个人资料更新。

接口列表


POST /auth/register

创建新用户账户。

请求体:

{
  "email": "user@example.com",
  "username": "inkuser",
  "password": "securePassword123"
}
字段 类型 必填 描述
email string 有效的邮箱地址
username string 唯一的用户名
password string 至少 8 个字符

响应: 201 Created

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "dGhpcyBpcyBhIHJlZnJl...",
  "user": {
    "id": "01912345-6789-7abc-def0-123456789abc",
    "email": "user@example.com",
    "username": "inkuser",
    "createdAt": "2026-01-15T10:30:00Z",
    "updatedAt": "2026-01-15T10:30:00Z"
  }
}

错误:

状态码 原因
400 字段缺失或格式无效
409 邮箱或用户名已被占用

POST /auth/login

使用邮箱或用户名加密码进行认证。

请求体:

{
  "identifier": "user@example.com",
  "password": "securePassword123"
}
字段 类型 必填 描述
identifier string 邮箱地址或用户名
password string 账户密码

响应: 200 OK

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "dGhpcyBpcyBhIHJlZnJl...",
  "user": {
    "id": "01912345-6789-7abc-def0-123456789abc",
    "email": "user@example.com",
    "username": "inkuser",
    "createdAt": "2026-01-15T10:30:00Z",
    "updatedAt": "2026-01-15T10:30:00Z"
  }
}

错误:

状态码 原因
400 字段缺失
401 凭据无效

POST /auth/refresh

使用有效的刷新令牌换取新的令牌对。旧的刷新令牌将被废止。

请求体:

{
  "refreshToken": "dGhpcyBpcyBhIHJlZnJl..."
}

响应: 200 OK

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "bmV3IHJlZnJlc2ggdG9r..."
}

错误:

状态码 原因
401 刷新令牌无效、已过期或已被使用

令牌轮换

刷新令牌为一次性使用。每次调用此接口都会废止之前的刷新令牌并返回新的令牌对。如果刷新令牌被重复使用,作为安全措施,该用户的所有会话可能会被撤销。


POST /auth/logout

:material-lock: 需要认证

撤销提供的刷新令牌,结束会话。

请求头:

Authorization: Bearer {accessToken}

请求体:

{
  "refreshToken": "dGhpcyBpcyBhIHJlZnJl..."
}

响应: 200 OK

{
  "message": "logged out"
}

错误:

状态码 原因
401 访问令牌缺失或无效

GET /auth/me

:material-lock: 需要认证

获取当前认证用户的个人资料,包括关联的 OAuth 账户和订阅状态。

请求头:

Authorization: Bearer {accessToken}

响应: 200 OK

{
  "id": "01912345-6789-7abc-def0-123456789abc",
  "email": "user@example.com",
  "username": "inkuser",
  "createdAt": "2026-01-15T10:30:00Z",
  "updatedAt": "2026-01-15T10:30:00Z",
  "oauthAccounts": [
    {
      "provider": "google",
      "providerUserId": "117382948271639",
      "email": "user@gmail.com",
      "linkedAt": "2026-01-20T14:00:00Z"
    }
  ],
  "subscription": {
    "status": "active",
    "plan": "pro",
    "interval": "monthly",
    "currentPeriodEnd": "2026-02-15T10:30:00Z",
    "cancelAtPeriodEnd": false
  }
}

提示

如果用户从未订阅过,subscription 字段为 null

错误:

状态码 原因
401 访问令牌缺失或无效

PUT /auth/me

:material-lock: 需要认证

更新当前认证用户的个人资料。所有字段均为可选 --- 只需包含你要修改的字段。

请求头:

Authorization: Bearer {accessToken}

请求体:

{
  "username": "newusername",
  "password": "newSecurePassword456",
  "currentPassword": "securePassword123"
}
字段 类型 必填 描述
username string 新用户名
password string 新密码(至少 8 个字符)
currentPassword string 条件必填 修改密码时必须提供当前密码

响应: 200 OK

{
  "id": "01912345-6789-7abc-def0-123456789abc",
  "email": "user@example.com",
  "username": "newusername",
  "createdAt": "2026-01-15T10:30:00Z",
  "updatedAt": "2026-01-16T08:00:00Z"
}

错误:

状态码 原因
400 字段无效或修改密码时未提供 currentPassword
401 访问令牌缺失或无效
409 用户名已被占用

GET /auth/sessions

:material-lock: 需要认证

列出当前认证用户的所有活跃会话。

请求头:

Authorization: Bearer {accessToken}

响应: 200 OK

[
  {
    "id": "01912345-0000-7abc-def0-000000000001",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
    "ip": "192.168.1.100",
    "createdAt": "2026-01-15T10:30:00Z",
    "lastUsedAt": "2026-01-16T08:00:00Z"
  },
  {
    "id": "01912345-0000-7abc-def0-000000000002",
    "userAgent": "InkletDesktop/1.0",
    "ip": "10.0.0.50",
    "createdAt": "2026-01-14T09:00:00Z",
    "lastUsedAt": "2026-01-15T22:00:00Z"
  }
]

错误:

状态码 原因
401 访问令牌缺失或无效

DELETE /auth/sessions/{id}

:material-lock: 需要认证

通过 ID 撤销指定会话。这将废止与该会话关联的刷新令牌。

路径参数:

参数 描述
id 会话 UUID

请求头:

Authorization: Bearer {accessToken}

响应: 200 OK

{
  "message": "session revoked"
}

错误:

状态码 原因
401 访问令牌缺失或无效
404 会话未找到或不属于当前用户

OAuth 接口

Inklet 支持 Google 登录和 Apple 登录。OAuth 流程使用服务端重定向。

GET /auth/oauth/google

发起 Google OAuth 登录。client 查询参数决定使用哪个重定向 URI。

查询参数:

参数 可选值 描述
client web, desktop, ios 发起登录流程的客户端平台

示例:

GET /auth/oauth/google?client=web

响应: 302 Found --- 重定向至 Google 的 OAuth 授权页面。


GET /auth/oauth/google/callback

处理来自 Google 的 OAuth 回调。此接口不由客户端直接调用 --- 用户授权后由 Google 重定向至此。

行为:

  • 如果该 Google 邮箱尚未注册,则创建新账户
  • 如果邮箱匹配已有用户,则关联 Google 账户
  • 通过重定向返回令牌(令牌作为查询参数或 fragment,取决于客户端类型)

GET /auth/oauth/apple

发起 Apple OAuth 登录。

查询参数:

参数 可选值 描述
client web, desktop, ios 发起登录流程的客户端平台

示例:

GET /auth/oauth/apple?client=web

响应: 302 Found --- 重定向至 Apple 的 OAuth 授权页面。


POST /auth/oauth/apple/callback

处理来自 Apple 的 OAuth 回调。Apple 使用 form_post 响应模式,因此此接口接收的是包含表单编码数据的 POST 请求,而非查询参数。

Apple OAuth 的不同之处

与 Google 不同,Apple 以 POST 请求发送回调,请求体为 application/x-www-form-urlencoded 格式。Apple 还仅在首次授权时提供用户姓名 --- 后续登录只包含邮箱。

行为:

  • 如果该 Apple 邮箱尚未注册,则创建新账户
  • 如果邮箱匹配已有用户,则关联 Apple 账户
  • 通过重定向返回令牌