身份与授权 · API 参考

API 参考

本页列出身份与授权服务的全部端点。分为三组:应用管理(/api/v1,浏览器调用)、应用成员组管理(/oauth,应用后端用 client_credentials 调用)、OAuth 协议端点(/oauth,授权 / 换 token / userinfo)。协议端点的参数与响应细节见授权码流程。

通用约定#

  • 路径前缀:应用管理面 /api/v1,协议面与管理面 /oauth(无前缀)。
  • 字段命名 snake_case,时间为 ISO 8601(UTC)。
  • 错误形状:管理面 { "detail": "中文说明" },协议面 { "error": "…", "error_description": "…" }。
  • 分页响应统一为 { items, total, page, per_page, pages }。

认证方式#

面调用方认证
应用管理(/api/v1)浏览器平台登录态(session cookie)
OAuth 协议(/oauth/token)应用后端client_id + client_secret(HTTP Basic 或表单二选一)
应用成员组管理(/oauth/* 管理 API)应用后端Authorization: Bearer <client_credentials token>
userinfo应用后端Authorization: Bearer <access_token>
jwks / discovery任意公开

一、应用管理#

创建应用#

群创建者操作。免审核,创建即激活。enable_client_credentials=true 时自动附带管理 scope。响应中 包含一次性 client_secret,请立即保存。

POST /api/v1/forums/{slug}/oauth-applications

请求体:

{
  "name": "示例应用",
  "description": "应用用途说明",
  "logo_url": "https://app.example.com/logo.png",
  "redirect_uri": "https://app.example.com/callback",
  "scopes": ["openid", "profile", "email", "group", "member_groups"],
  "enable_client_credentials": true
}

响应 201(节选,client_secret 仅本次返回):

{
  "id": 3,
  "client_id": "app_9f8e7d6c5b4a3f2e1d0c",
  "client_secret": "jX3kQ9mN2vB7cL4pR8tW1yZ6aE0dF5gH",
  "name": "示例应用",
  "redirect_uri": "https://app.example.com/callback",
  "scopes": ["openid", "profile", "email", "group", "member_groups", "members:read", "member_groups:write"],
  "grant_types": ["authorization_code", "client_credentials"],
  "status": "active"
}
状态码含义
201创建成功并激活
400scope 不合法或回调地址不合法
403调用者不是群创建者

查看本群应用#

GET /api/v1/forums/{slug}/oauth-applications

群创建者与管理员可调用,返回 OAuthApplicationOut 数组。

编辑 / 移除 / 重置 Secret#

PATCH  /api/v1/forums/{slug}/oauth-applications/{id}            # 编辑名称、描述、Logo、回调、scope、client_credentials
DELETE /api/v1/forums/{slug}/oauth-applications/{id}            # 移除应用,吊销全部 token
POST   /api/v1/forums/{slug}/oauth-applications/{id}/rotate-secret  # 重置 secret,一次性返回,旧值立即失效

回调地址与 scope 的变更对 新发起的授权 生效,已签发的 token 不受影响。

管理员:禁用 / 恢复#

GET  /api/v1/admin/oauth-applications?status_filter=active   # 列表,可过滤 active / disabled
POST /api/v1/admin/oauth-applications/{id}/disable           # 禁用,吊销该应用全部 token
POST /api/v1/admin/oauth-applications/{id}/enable            # 恢复被禁用的应用

列表端点返回 AdminOAuthApplicationOut 数组(非分页信封),按创建时间倒序,默认 50 条。

用户撤销授权#

GET    /api/v1/me/oauth-grants              # 我授权过的应用列表
DELETE /api/v1/me/oauth-grants/{client_id}  # 撤销授权,吊销该应用名下我的 token

二、应用成员组管理(client_credentials)#

先换取管理凭据(此步无用户参与):

curl -X POST https://mooc.pneumas.org/oauth/token \
  -u YOUR_CLIENT_ID:YOUR_CLIENT_SECRET \
  -d grant_type=client_credentials \
  -d scope="members:read member_groups:write"
{ "access_token": "…", "token_type": "Bearer", "expires_in": 3600, "scope": "members:read member_groups:write" }

此后所有管理接口携带 Authorization: Bearer <cc_token>。上下文固定为应用绑定的群,无需也不能传群 ID;访问其他群的数据一律返回 404,不暴露存在性。

应用成员组 CRUD#

方法路径所需 scope说明
GET/oauth/member-groupsmembers:read全部成员组,含默认组
POST/oauth/member-groupsmember_groups:write创建;请求体 {name, description?, sort?, is_default?};同名 409
PATCH/oauth/member-groups/{id}member_groups:write修改名称 / 描述 / 排序 / 设默认;默认组不可取消默认标记
DELETE/oauth/member-groups/{id}member_groups:write默认组不可删;组内仍有成员 → 409;组映射了课程 → 409

创建示例:

curl -X POST https://mooc.pneumas.org/oauth/member-groups \
  -H "Authorization: Bearer $CC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "高级会员", "description": "可访问进阶内容"}'
{
  "id": 12,
  "forum_id": 7,
  "name": "高级会员",
  "description": "可访问进阶内容",
  "sort": 0,
  "is_default": false,
  "member_count": 1,
  "member_ids": [10042]
}

群成员列表#

GET /oauth/members?page=1&per_page=20     # 所需 scope:members:read

page 默认 1,per_page 默认 20、范围 1–100。返回分页信封:

{
  "items": [
    {
      "user_id": 10042,
      "username": "user_10042",
      "display_name": "用户 10042",
      "avatar_url": null,
      "member_group_ids": [11, 12],
      "joined_at": "2026-08-17T12:00:00+00:00"
    }
  ],
  "total": 1, "page": 1, "per_page": 20, "pages": 1
}

成员应用成员组分配#

方法路径说明
POST/oauth/members/{user_id}/member-groups/{group_id}将 已有群成员 加入应用成员组;非群成员 → 409,不会自动拉人进群
DELETE/oauth/members/{user_id}/member-groups/{group_id}移出应用成员组;该用户的最后一个应用成员组 → 409,需改用 /move
POST/oauth/members/{user_id}/member-groups/{group_id}/move表单字段 target_group_id,原子地从一个应用成员组移到另一个

将用户 10042 从默认应用成员组(11)移到"高级会员"(12):

curl -X POST https://mooc.pneumas.org/oauth/members/10042/member-groups/11/move \
  -H "Authorization: Bearer $CC_TOKEN" \
  -d target_group_id=12

写操作会同步平台侧的课程权益:成员应用成员组变更后,对应课程的开通与收回随之更新。在应用侧修改应用成员组,平台群管理页面立即可见。

成员准入只在群管理:管理 API 只能操作 已有群成员 的应用成员组分配,不能把非成员拉进群。新成员加入群由群创建者 / 管理员在平台侧完成。

三、OAuth 协议端点#

端点说明
GET /oauth/authorize授权码流程起点
POST /oauth/token换 token、刷新、client_credentials
GET /oauth/userinfo用户身份与应用成员组
GET /oauth/jwksRS256 公钥
GET /.well-known/openid-configuration发现端点

参数与响应定义见授权码流程。

错误码#

协议面(authorize / token / userinfo)#

errorHTTP出现条件
invalid_request400参数缺失、非法或超长
invalid_client400client_id / client_secret 错误,或应用未激活 / 被禁用
invalid_grant400code 已用 / 过期 / 不匹配;refresh 失效;PKCE 校验失败
unauthorized_client400客户端未被授权使用该 grant_type
invalid_scope400申请了未获批或白名单外的 scope
insufficient_scope403管理 API 的 token 缺少所需 scope
invalid_token401userinfo / 管理 API 的 token 无效、过期或已吊销(携带 WWW-Authenticate 头)
access_denied—用户在同意页点了拒绝(经回调 ?error= 返回,非 HTTP 错误)

管理面(/api/v1)#

HTTP出现条件
400scope 或回调地址不合法
403调用者不是群创建者 / 管理员;非管理员访问管理接口
404群、应用或授权记录不存在
409状态不允许该操作(如编辑被禁用的应用、重复禁用、成员组同名、删除有成员的成员组)