GitHub

Token 与错误码

返回 README


JWT Access Token Claims

Header 携带 typ: at+jwt(RFC 9068 access token 类型标记);claims:

{
  "sub": "用户UUID",
  "id": 12345,
  "email": "邮箱",
  "name": "用户名",
  "roles": ["admin", "ren"],
  "site_roles": ["moderator"],
  "scope": "openid profile",
  "site_id": 2,
  "client_id": "签发给的 OAuth client",
  "iss": "https://oauth.kungal.com",
  "aud": ["www.moyu.moe"],
  "jti": "随机 token id",
  "exp": 1700000000,
  "iat": 1699999100,
  "nbf": 1699999100
}
  • iss 固定为 OP issuer({issuer}/.well-known/openid-configurationissuer)。
  • aud 是资源方标识 = 该 client 绑定站点的域名(RFC 9068 audience 限制);client 未绑定站点时省略。下游现有的站点校验仍以 site_id 为准aud 供标准校验器使用。
  • scope / site_id / client_id / site_roles 在对应值为空时省略。

签名算法:HS256(现状)。OIDC 切换(KUN_OIDC_SIGN_ASYMMETRIC)后改为 ES256(header 带 kid,公钥见 {issuer}/oauth/jwks);切换窗口内两种签名都会被各服务接受,下游把 access_token 当不透明字符串用即可,不要对签名算法做硬编码假设。

roles 是角色名的集合,普通用户为空数组 []user 是隐式默认,不会出现在 claim 里)。角色及其能力语义的权威定义、以及下游必须遵守的规则,见 11-roles.mdsite_roles(可选)是站点域角色——只含用户在本 client 所属站点的未过期授予,与 roles 取并集后喂给你既有的能力判定;权威定义见 12-site-roles.md


错误码速查

所有错误的响应体格式都是:

{ "code": <int>, "message": "<中文消息>" }

code = 0 表示成功;其余按下面分类查阅。

OAuth 错误 (15xxx)

Code HTTP 消息 说明
15001 400 无效的客户端 client_id 不存在
15002 400 无效的回调地址 redirect_uri 未注册
15003 400 无效的授权码 code 已过期 / 已使用 / 不存在
15004 400 无效的代码验证器 PKCE code_verifier 不匹配
15005 400 客户端未被授权使用该授权类型 client 的 grants 列里没有当前 grant_type — 常见:admin 创建 client 时漏勾 refresh_token。RP 应按「refresh 已死 → 强制重新登录」处理
15006 400 无效的权限范围 请求的 scope 不在 client 的 allowed_scopes
15007 400 访问被拒绝 用户拒绝授权
15008 400 无效的 client secret confidential client 没传或填错 client_secret
15009 400 需要 PKCE public client 没传 code_verifier
15011 400 不支持的授权类型 grant_type 本身不被实现(仅 authorization_code / refresh_token

标准 wire 格式下的错误(RFC 6749)

OP 切换 KUN_OIDC_STANDARD_WIRE 后,/oauth/token/oauth/userinfo/oauth/revoke 的错误改为标准 OAuth 错误对象 {"error": "...", "error_description": "..."}(不再有 code 字段)。错误字符串与上表错误码的对应:

error 对应错误码 RP 处理
invalid_client 15001 / 15008 配置错误(client_id / secret),refresh 已死
invalid_grant 15002 / 15003 / 15004 / 10002 / 10003 / 10014 授权凭据无效或会话已死 → 强制重新登录
unauthorized_client 15005 client 未被允许该 grant → refresh 已死
invalid_scope 15006 scope 配置错误
unsupported_grant_type 15011 请求 bug(grant_type 写错)
invalid_request 其他 请求格式问题

一方 RP 的宽容读取器必须把 invalid_grant / unauthorized_client / invalid_client 分类为「refresh 已死」(清会话、要求重新登录),未知字符串才当瞬态错误重试 —— 否则死会话会无限重试。

认证错误 (10xxx)

Code HTTP 消息 说明
10001 401 未授权 未提供 Bearer Token
10002 401 无效的令牌 Token 格式错误 / 签名无效 / refresh 时 client_id 与签发时的不匹配
10003 401 令牌已过期 access_token 或 refresh_token 已过期,需要刷新或重新登录
10004 400 邮箱或密码错误 登录或 PUT /auth/password 时旧密码不匹配
10005 401 用户不存在 UUID 对应的用户不存在(账号被硬删等罕见情况)
10006 400 该邮箱已被注册 改邮箱 / 注册(send-code 或 register 阶段)时邮箱已存在
10007 400 用户名已存在 PATCH /auth/me 改 name / 注册时用户名重复
10010 400 验证码无效 改邮箱 / 注册时 6 位码错误(或与 send-code 时提交的 email 不一致)
10011 400 验证码已过期 验证码过期(默认 15 分钟,由 KUN_AUTH_VERIFICATION_CODE_TTL_MINUTES 控制)或从未请求;常见来源:用户修改了 email 后没重发码
10012 400 邮箱验证码发送过于频繁 上一次 send-code 距今不足限流间隔(改邮箱按 user 限流 / 注册按 email 限流)
10013 400 新邮箱与当前邮箱相同 改邮箱 send-code 时检测;不消耗验证码额度
10014 403 账号已封禁 用户被 admin 封号 — 前端应跳错误页("账号被封禁")而非登录页,让用户再登也是同样的 403

通用错误

Code 消息 触发场景示例
1 请求格式错误 JSON 语法错 / multipart 解析失败 / 上游服务(如 image_service)报错
7 参数验证失败 字段长度 / 格式校验未通过
8 缺少必要参数 必填字段没传(如 multipart 缺 file
9 参数无效 类型不对 / 超出范围(如 ids 个数 >100、limit 不是正整数)
10 操作失败 一般是 DB 写入失败、外部服务异常等内部错误

源:kun-galgame-infra/docs/integration/oauth/04-tokens-and-errors.md