用户授权 OAuth2

服务端 API 更新于 2026-09-21 阅读 14

阅读指引:本篇是《开放平台服务端 API 指南》的第 4 部分。接口基础地址、通用约定与各接口请求限制,请先阅读《服务端 API 概览》。

3. 应用权限与用户授权

管理员授予的是应用能力上限;用户 OAuth2 授权是该上限内当前用户同意的范围;应用发布范围决定用户使用应用及用户、组织接口的资源边界;群接口另外以应用与目标群的有效绑定为授权依据。三者不能互相替代。

Scope 类型 入口 状态
user:profile:read 需要用户授权 GET /openapi/v1/user/profile 可用
material:manage 应用能力,默认授权 POST /openapi/v1/materials<br>GET /openapi/v1/materials/content 可用
contact:organization:read 应用能力,需管理员授权 GET/POST /openapi/v1/organization/* 可用
chat:conversation:choose 应用能力,默认授权 JSAPI chooseChat,需要 config 可用
chat:conversation:open 应用能力,需管理员授权 JSAPI openChat,需要 config 可用
group:app 应用能力,需管理员授权并由群主/管理员添加到群 GET /openapi/v1/groups/*POST /openapi/v1/messages/sendrecipient.type=group 可用
message:send:user 应用能力,默认授权 POST /openapi/v1/messages/sendrecipient.type=user 可用
message:send:org_node 应用能力,需管理员授权 POST /openapi/v1/messages/sendrecipient.type=org_node 可用
message:send:all 应用能力,需管理员授权 POST /openapi/v1/messages/sendrecipient.type=all 可用
message:delegate:send 需要用户授权 POST /openapi/v1/messages/delegate_sendrecipient.type=user/group 可用
  1. 应用只能取得管理员已授予 Scope 的 Token。
  2. 用户 OAuth2 只能申请 requires_user_auth=true 的 Scope。
  3. 权限变更后既有 access token 和 refresh token 被撤销,应用必须重新认证。
  4. 应用不能根据 Scope 名称猜测接口;以本文公开入口及应用实际获授能力为准。
  5. 用户和组织接口受第 12 章发布范围约束。群资料和群成员读取以 group:app 与有效群绑定为依据,返回绑定群的成员,不按用户或组织发布范围逐个裁剪。

5. 普通 H5 OAuth2 模式

适用于在平台兼容客户端中打开的 H5,直接导航 OAuth2 authorize URL、不使用 JSSDK getAuthCode 的场景。H5 只需构造授权地址,当前登录用户由客户端提供。普通外部浏览器仅打开此地址不能建立平台用户身份,也不能完成授权;不要把它用作独立网页登录入口。

H5 导航 /oauth2/authorize
  → 平台验证当前登录用户、应用状态、发布范围、回调地址和 Scope
  → 302 跳转到已登记的 redirect_uri,携带 code/state
  → 应用后端校验 state,并用 app_key + app_secret 换用户 Token

GET /openapi/v1/oauth2/authorize

https://openapi.example.com/openapi/v1/oauth2/authorize
  ?client_id=svc_app_xxx
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback
  &response_type=code
  &scope=user%3Aprofile%3Aread
  &state=csrf_random_value
query 参数 类型 必填 规则
client_id string 固定为应用 app_key;首尾空白会被去除。
redirect_uri string 必须与管理员登记的完整回调 URI 精确一致,包括协议、主机、端口、路径和 query;不支持通配符或 fragment。
response_type string 固定为 code
scope string 一个或多个需要用户授权、且已由管理员授予应用的 Scope;多个值以单个空格分隔。
state string 应用生成的非空 UTF-8 高熵随机值,最多 256 字节;平台原样返回,应用必须校验以防止 CSRF 和请求串线。

静默授权从兼容的已登录客户端进入并符合授权条件时,授权可能直接完成并返回 code,不一定展示确认页。应用必须按回调结果处理,不能假设每次都弹出授权确认,也不能自行模拟用户身份。

发布范围会在授权链路中重复检查authorize、authorization code 换 Token、用户 Token 刷新以及后续用户接口都会按当前范围复核。用户被移出范围后,应用应结束该用户会话,不要继续刷新旧 Token。

authorize 结果 HTTP 行为 字段
成功 302 Found 跳转到已登记的 redirect_uri code:短期、一次性 authorization code;state:请求值原样返回。
可安全回调的失败 302 Found 跳转到已验证属于该应用的 redirect_uri errorerror_description 和原始 state
无法信任回调地址的失败 HTTP 400 或 500 JSON error 与可选 error_description;不会跳转到未验证地址。

用 code 换用户 Token

curl -X POST "${OPENAPI_BASE_URL}/openapi/v1/oauth2/token" \
  -u "${APP_KEY}:${APP_SECRET}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=authorization_code" \
  --data-urlencode "code=${AUTHORIZATION_CODE}" \
  --data-urlencode "redirect_uri=https://app.example.com/oauth/callback"
请求字段 必填 类型与规则
grant_type string;固定为 authorization_code
code string;authorize 回调或 JSSDK getAuthCode 返回的短期一次性 code。
redirect_uri string;必须与申请 code 时使用的值完全一致。
客户端凭据 该 code 所属应用的 app_key + app_secret,推荐使用 HTTP Basic。
{
  "access_token": "atk_mim_user_xxx",
  "refresh_token": "rtk_mim_user_xxx",
  "expires_in": 7200,
  "refresh_expires_in": 2592000,
  "token_type": "Bearer",
  "scope": "user:profile:read",
  "client_id": "svc_app_xxx",
  "user_open_id": "10001"
}
响应字段 JSON 类型 含义与单位
access_token string 代表当前应用和当前授权用户的用户访问令牌。
refresh_token string 用户级刷新令牌;只能由应用后端保存。
expires_in integer access token 剩余有效时间,单位秒。
refresh_expires_in integer refresh token 剩余有效时间,单位秒。
token_type string 固定为 Bearer
scope string 用户实际授权的 Scope,以单个空格分隔。
client_id string 应用的 app_key
user_open_id string 当前应用可使用的用户标识;按不透明字符串保存和比较。

刷新用户 Token

仍调用同一 Token endpoint。服务端从 refresh token 的可信上下文识别它是用户 Token,不能通过请求字段把应用 Token 改成用户 Token。

curl -X POST "${OPENAPI_BASE_URL}/openapi/v1/oauth2/token" \
  -u "${APP_KEY}:${APP_SECRET}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=refresh_token" \
  --data-urlencode "refresh_token=${USER_REFRESH_TOKEN}"

撤销当前用户授权

POST /openapi/v1/oauth2/user_authorization/revoke

curl -X POST "${OPENAPI_BASE_URL}/openapi/v1/oauth2/user_authorization/revoke" \
  -H "Authorization: Bearer ${USER_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"scope":"user:profile:read"}'
请求字段 必填 类型与规则
scope string;传入时撤销当前用户的这一个 Scope,空字符串或省略时撤销当前用户在该应用下的全部授权。

请求不传用户 ID。平台只操作 Bearer Token 对应的当前应用与当前用户,并使相关用户 access/refresh token 失效。

{
  "code": 200,
  "message": "ok",
  "data": {
    "app_id": 4611686018427397904,
    "user_open_id": "10001",
    "revoked_rows": 1
  }
}
响应字段 JSON 类型 含义
code integer 业务码;成功为 200
message string 简短结果文本;业务判断以 code 为准。
data.app_id integer 保留字段;应用不应持久化或依赖该字段。
data.user_open_id string 被撤销授权的当前用户标识。
data.revoked_rows integer 实际撤销的授权记录数量,无单位;没有匹配的有效授权记录时可能为 0。成功撤销后当前 Token 已失效,不应使用它再次调用撤销接口。

6. JSSDK OAuth2 模式

getAuthCode 用于在 H5 内获取当前登录用户的 authorization code。该 JSAPI 已开放,必须在 ready 后调用,但不要求先执行 config。H5 只需提交文档列出的应用、回调地址、Scope 和 state 参数。

const result = await im.openPlatform.getAuthCode({
  appKey: "svc_app_xxx",
  redirectUri: "https://app.example.com/oauth/callback",
  scopes: ["user:profile:read"],
  state: crypto.randomUUID()
})

// result.authorizationCode / result.state / result.expiresIn
// 将 code 交给应用后端,后端仍使用 app_key + app_secret 换 Token。
请求字段 JS 类型 必填 规则
appKey string 当前应用的 app_key;它是公开选择器,不是身份凭据。
redirectUri string 必须与管理员登记的完整 OAuth2 回调 URI 精确一致。
scopes string[] 非空数组;每项是一个不含空白的用户授权 Scope,必须已授予当前应用且要求用户授权。
state string 非空 UTF-8 字符串,最多 256 字节;应用生成并在换码链路中校验。
成功结果字段 JS 类型 含义与单位
authorizationCode string 短期、一次性 OAuth2 code,只应交给应用后端换用户 Token。
state string 请求值原样返回;应用必须与发起请求时保存的值比较。
expiresIn number authorization code 剩余有效时间,单位秒。
H5 getAuthCode
  → 平台验证当前登录用户、应用发布范围、应用页面、回调地址和 Scope
  → 成功后返回短期、一次性的 code
  → 应用后端使用 code 换取用户 Token

当前用户和运行环境由平台识别,H5 只提交上述已文档化参数,不要附加用户身份、登录凭据或运行环境参数。调用失败时 Promise reject,错误对象使用第 11.6 节定义的统一 code/message/requestId/details 结构。

7. 获取当前授权用户信息与头像

GET /openapi/v1/user/profile

要求用户态 Bearer Token,并同时具备应用 Scope 和用户授权 Scope user:profile:read;当前用户还必须仍在应用发布范围内。

请求项 必填 规则
Authorization Header Bearer {USER_ACCESS_TOKEN};不接受应用级 Token。
query/body 本接口没有 query 参数和请求 body;用户身份只来自 Token。
curl "${OPENAPI_BASE_URL}/openapi/v1/user/profile" \
  -H "Authorization: Bearer ${USER_ACCESS_TOKEN}"
{
  "code": 200,
  "message": "ok",
  "data": {
    "user_open_id": "10001",
    "name": "张三",
    "avatar": {
      "thumbnail_url": "https://openapi.example.com/openapi/v1/media/avatar/thumbnail?resource=opaque_xxx",
      "original_url": "https://openapi.example.com/openapi/v1/media/avatar/original?resource=opaque_yyy",
      "expires_at": 1787400300
    }
  }
}
响应字段 JSON 类型 含义与单位
code integer 业务码;成功为 200
message string 简短结果文本;业务判断以 code 为准。
data.user_open_id string 当前应用下的用户标识,按不透明字符串处理。
data.name string 用户当前展示名称,可能随用户资料变化。
data.avatar.thumbnail_url string 短期缩略头像 URL。
data.avatar.original_url string 短期原始头像 URL。
data.avatar.expires_at integer 两条头像 URL 的失效时间,Unix 秒时间戳。

下载头像

GET /openapi/v1/media/avatar/{thumbnail|original}?resource={opaque}

curl -L "${THUMBNAIL_URL}" -o avatar-thumbnail.jpg
下载项 规则
路径参数 thumbnail 下载缩略图;original 下载原图。
resource 必填且只能出现一次;完整使用 profile 返回的不透明值,不得解析、修改或重复编码。
成功响应 HTTP 200,body 为图片二进制;Content-Type 由实际头像文件决定,不使用 JSON 包装。
失败响应 篡改、过期、规格错误、文件不存在或回源失败统一为 HTTP 404 空 body。
  • 只使用响应中的下载 URL 获取头像,不要推断或拼接其他文件地址;URL 绑定应用、用户、文件规格与到期时间。
  • 默认有效期 5 分钟,部署上限 15 分钟;过期后重新请求 profile。
  • 下载 URL 不需要再次提交 Token。篡改、过期、文件不存在或回源失败统一返回 HTTP 404 空响应。
  • 应用只能查询 Token 对应的当前用户,接口不接收 user_id/user_open_id