[{"data":1,"prerenderedAt":28},["ShallowReactive",2],{"doc:\u002Fcontracts\u002Foauth\u002F01-oauth-endpoints":3},{"title":4,"route":5,"toc":6,"segments":23,"source":27},"OAuth 2.0 端点","\u002Fcontracts\u002Foauth\u002F01-oauth-endpoints",[7,11,14,17,20],{"id":8,"text":9,"depth":10},"post-oauth-token","POST \u002Foauth\u002Ftoken",2,{"id":12,"text":13,"depth":10},"get-oauth-authorize","GET \u002Foauth\u002Fauthorize",{"id":15,"text":16,"depth":10},"get-oauth-userinfo","GET \u002Foauth\u002Fuserinfo",{"id":18,"text":19,"depth":10},"post-oauth-revoke","POST \u002Foauth\u002Frevoke",{"id":21,"text":22,"depth":10},"登出-rp-initiated-logout","登出（RP-Initiated Logout）",[24],{"type":25,"html":26},"html","\u003Ch1 id=\"oauth-2-0-端点\" tabindex=\"-1\">OAuth 2.0 端点\u003C\u002Fh1>\n\u003Cp>返回 \u003Ca href=\"\u002Fcontracts\u002Foauth\">README\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>本节是 OAuth 2.0 Authorization Code（含 PKCE）+ Refresh Token 协议的端点契约。完整的对接走查（环境变量、回调处理、并发刷新、安全注意事项）请看 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002Foauth-integration-guide\">oauth-integration-guide.md\u003C\u002Fa>，Nuxt 快速上手见 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002Fnuxt-integration-prompt\">nuxt-integration-prompt.md\u003C\u002Fa>。\u003C\u002Fp>\n\u003Cdiv class=\"kun-table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>端点\u003C\u002Fth>\n\u003Cth>方法\u003C\u002Fth>\n\u003Cth>鉴权\u003C\u002Fth>\n\u003Cth>用途\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Foauth\u002Fauthorize\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>GET\u003C\u002Ftd>\n\u003Ctd>终端用户 Bearer Token\u003C\u002Ftd>\n\u003Ctd>用户同意授权后拿授权码\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Foauth\u002Ftoken\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>POST\u003C\u002Ftd>\n\u003Ctd>client_id+secret（或 PKCE）\u003C\u002Ftd>\n\u003Ctd>授权码 \u002F refresh_token 换 access_token\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Foauth\u002Fuserinfo\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>GET\u003C\u002Ftd>\n\u003Ctd>Bearer Token\u003C\u002Ftd>\n\u003Ctd>读用户公开信息（受 scope 控制）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Foauth\u002Frevoke\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>POST\u003C\u002Ftd>\n\u003Ctd>不需要\u003C\u002Ftd>\n\u003Ctd>主动吊销 token（登出）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Foauth\u002Flogout\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>GET\u003C\u002Ftd>\n\u003Ctd>不需要\u003C\u002Ftd>\n\u003Ctd>RP 登出入口：顶层导航，302 跳 OP 前端登出页（见 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002F07-logout\">07\u003C\u002Fa>）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Foauth\u002Fpost-logout-redirect\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>GET\u003C\u002Ftd>\n\u003Ctd>不需要\u003C\u002Ftd>\n\u003Ctd>登出回跳白名单校验（见 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002F07-logout\">07\u003C\u002Fa>）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Chr>\n\u003Ch2 id=\"post-oauth-token\" tabindex=\"-1\">POST \u002Foauth\u002Ftoken\u003C\u002Fh2>\n\u003Cp>用授权码或刷新令牌换取 access token。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>请求体（授权码模式）\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-json\">\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"grant_type\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"authorization_code\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"code\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"64位hex授权码\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"redirect_uri\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"https:\u002F\u002Fwww.kungal.com\u002Fauth\u002Fcallback\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"client_id\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"your-client-id\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"client_secret\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"your-client-secret\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"code_verifier\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"PKCE验证器（如果authorize时使用了code_challenge）\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>请求体（刷新令牌模式）\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-json\">\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"grant_type\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"refresh_token\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"refresh_token\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"eyJhbGc...\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"client_id\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"your-client-id\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"client_secret\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"your-client-secret\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>成功响应\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-json\">\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"code\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"message\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"成功\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"data\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"access_token\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"eyJhbGc...\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"token_type\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"Bearer\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"expires_in\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">900\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"refresh_token\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"eyJhbGc...\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"scope\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"openid profile\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cdiv class=\"kun-table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>字段\u003C\u002Fth>\n\u003Cth>说明\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>access_token\u003C\u002Ftd>\n\u003Ctd>JWT，有效期 15 分钟\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>token_type\u003C\u002Ftd>\n\u003Ctd>固定 &quot;Bearer&quot;\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>expires_in\u003C\u002Ftd>\n\u003Ctd>900 秒（15 分钟）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>refresh_token\u003C\u002Ftd>\n\u003Ctd>JWT，有效期 7 天。每次刷新会轮换\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>scope\u003C\u002Ftd>\n\u003Ctd>可选，回显授权时的 scope\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Cblockquote>\n\u003Cp>\u003Cstrong>限流\u003C\u002Fstrong>：此端点用 client_id 维度限流（不是 IP），所以 kungal\u002Fmoyu 这种走 SSR 后端代理整个用户群的 confidential client 不会被踢到匿名 IP 桶里。一般不会撞到上限。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Chr>\n\u003Ch2 id=\"get-oauth-authorize\" tabindex=\"-1\">GET \u002Foauth\u002Fauthorize\u003C\u002Fh2>\n\u003Cp>获取授权码。用户必须已登录（带 Bearer Token）。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>查询参数\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cdiv class=\"kun-table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>参数\u003C\u002Fth>\n\u003Cth>必填\u003C\u002Fth>\n\u003Cth>说明\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>client_id\u003C\u002Ftd>\n\u003Ctd>是\u003C\u002Ftd>\n\u003Ctd>OAuth 客户端 ID\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>redirect_uri\u003C\u002Ftd>\n\u003Ctd>是\u003C\u002Ftd>\n\u003Ctd>回调地址，必须与注册时一致\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>response_type\u003C\u002Ftd>\n\u003Ctd>是\u003C\u002Ftd>\n\u003Ctd>固定 \u003Ccode>code\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>state\u003C\u002Ftd>\n\u003Ctd>是\u003C\u002Ftd>\n\u003Ctd>随机字符串，防 CSRF\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>scope\u003C\u002Ftd>\n\u003Ctd>否\u003C\u002Ftd>\n\u003Ctd>权限范围，空格分隔\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>code_challenge\u003C\u002Ftd>\n\u003Ctd>否\u003C\u002Ftd>\n\u003Ctd>PKCE code challenge\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>code_challenge_method\u003C\u002Ftd>\n\u003Ctd>否\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>S256\u003C\u002Fcode>（默认）或 \u003Ccode>plain\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>prompt\u003C\u002Ftd>\n\u003Ctd>否\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>login\u003C\u002Fcode> = 强制重新登录（即使 OP 仍有会话也不静默放行）；见 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002F07-logout\">07-logout.md\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Cp>\u003Cstrong>成功响应\u003C\u002Fstrong>：HTTP 302 重定向到 \u003Ccode>redirect_uri?code=xxx&amp;state=xxx\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cp>\u003Cstrong>授权码有效期\u003C\u002Fstrong>：10 分钟，一次性使用。\u003C\u002Fp>\n\u003Chr>\n\u003Ch2 id=\"get-oauth-userinfo\" tabindex=\"-1\">GET \u002Foauth\u002Fuserinfo\u003C\u002Fh2>\n\u003Cp>获取当前登录用户信息。OIDC 标准端点；scope 控制下哪些字段会被返回。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>请求头\u003C\u002Fstrong>：\u003Ccode>Authorization: Bearer &lt;access_token&gt;\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cp>\u003Cstrong>成功响应\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-json\">\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"code\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"message\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"成功\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"data\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"id\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">12345\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"sub\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"550e8400-e29b-41d4-a716-446655440000\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"name\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"KUN\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"email\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"kun@kungal.com\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"picture\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"https:\u002F\u002F...\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"roles\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: [\u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"user\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"admin\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">    \"updated_at\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">1234567890\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cdiv class=\"kun-table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>字段\u003C\u002Fth>\n\u003Cth>说明\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>id\u003C\u002Ftd>\n\u003Ctd>用户整数 ID（= OAuth \u003Ccode>users.id\u003C\u002Fcode>，与 kungal\u002Fmoyu 业务表的 \u003Ccode>user_id\u003C\u002Fcode> 外键对齐）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>sub\u003C\u002Ftd>\n\u003Ctd>用户 UUID（OIDC 标准的 subject），与 \u003Ccode>id\u003C\u002Fcode> 标识同一用户，调用方任选其一\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>name\u003C\u002Ftd>\n\u003Ctd>用户名（仅 \u003Ccode>profile\u003C\u002Fcode> scope 或空 scope 时返回）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>email\u003C\u002Ftd>\n\u003Ctd>邮箱（仅 \u003Ccode>email\u003C\u002Fcode> scope 或空 scope 时返回）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>picture\u003C\u002Ftd>\n\u003Ctd>头像 URL（仅 \u003Ccode>profile\u003C\u002Fcode> scope 或空 scope 时返回，可能为空）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>roles\u003C\u002Ftd>\n\u003Ctd>角色名称数组，与 JWT \u003Ccode>roles\u003C\u002Fcode> claim 一致\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>updated_at\u003C\u002Ftd>\n\u003Ctd>最后更新时间（Unix 时间戳）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Cp>\u003Cstrong>关于 scope 与字段过滤\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cp>\u003Ccode>id\u003C\u002Fcode>、\u003Ccode>sub\u003C\u002Fcode>、\u003Ccode>roles\u003C\u002Fcode> 始终返回（不被 scope 过滤）—— 因为这三项已经在 JWT 里，调用方既然能用这个 JWT 调 \u002Fuserinfo，就已经拿到了这些信息，再隐藏没有意义。\u003Ccode>name\u003C\u002Fcode>、\u003Ccode>email\u003C\u002Fcode>、\u003Ccode>picture\u003C\u002Fcode> 按 OIDC 标准受 \u003Ccode>profile\u003C\u002Fcode> \u002F \u003Ccode>email\u003C\u002Fcode> scope 控制。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>跨服务接入提示\u003C\u002Fstrong>：kungal\u002Fmoyu\u002Fgalgame_wiki 后端处理 OAuth callback 时，应该在登录环节就拿 \u003Ccode>id\u003C\u002Fcode> 入库（作为本地 user 表的主键 \u002F 外键），不要只存 \u003Ccode>sub\u003C\u002Fcode> —— 后续业务表关联、\u003Ccode>\u002Fusers\u002Fbatch\u003C\u002Fcode> 批量回拉、SDK 缓存键，全部基于 \u003Ccode>id\u003C\u002Fcode> 整数键。\u003C\u002Fp>\n\u003Cp>想拿更全字段（如 \u003Ccode>moemoepoint\u003C\u002Fcode>、\u003Ccode>bio\u003C\u002Fcode>、\u003Ccode>avatar_image_hash\u003C\u002Fcode>）可以走 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002F02-user-profile#get-authme\">GET \u002Fauth\u002Fme\u003C\u002Fa>；想批量回拉多个用户走 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002F03-cross-service#get-usersbatch\">GET \u002Fusers\u002Fbatch\u003C\u002Fa>。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Chr>\n\u003Ch2 id=\"post-oauth-revoke\" tabindex=\"-1\">POST \u002Foauth\u002Frevoke\u003C\u002Fh2>\n\u003Cp>吊销令牌。遵循 RFC 7009，无论成功失败都返回 200。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>请求体\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-json\">\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">  \"token\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"要吊销的 refresh_token\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Chr>\n\u003Chr>\n\u003Ch2 id=\"登出-rp-initiated-logout\" tabindex=\"-1\">登出（RP-Initiated Logout）\u003C\u002Fh2>\n\u003Cp>登出 \u002F 单点登出是单独的跨服务契约，完整说明见 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002F07-logout\">07-logout.md\u003C\u002Fa>。要点：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>RP 登出须\u003Cstrong>顶层跳转\u003C\u002Fstrong>到 OP 登出入口 \u003Ccode>GET {OAUTH_API_BASE}\u002Foauth\u002Flogout?client_id=&amp;redirect=\u003C\u002Fcode>（复用访问 \u003Ccode>\u002Foauth\u002Fauthorize\u003C\u002Fcode> 的同一 base；后端 302 跳到 OP 前端登出页清会话再回跳）。\u003C\u002Fli>\n\u003Cli>\u003Ccode>GET \u002Foauth\u002Fpost-logout-redirect?client_id=&amp;redirect=\u003C\u002Fcode> 做回跳白名单校验（origin 匹配注册的 \u003Ccode>redirect_uri\u003C\u002Fcode>）。\u003C\u002Fli>\n\u003Cli>\u003Ccode>GET \u002Foauth\u002Fauthorize\u003C\u002Fcode> 的 \u003Ccode>prompt=login\u003C\u002Fcode> 可强制重新登录（仅登出本站语义的替代方案）。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Chr>\n\u003Cp>错误码（15001 - 15009）的详细含义见 \u003Ca href=\"\u002Fcontracts\u002Foauth\u002F04-tokens-and-errors#oauth-%E9%94%99%E8%AF%AF-15xxx\">04-tokens-and-errors.md §OAuth 错误\u003C\u002Fa>。\u003C\u002Fp>\n","kun-galgame-infra\u002Fdocs\u002Fintegration\u002Foauth\u002F01-oauth-endpoints.md",1781708341787]