接入文档
概述
Fusion OAuth 提供标准 OAuth 2.0 授权码模式与 OpenID Connect 能力。第三方应用通过授权码换取 Access Token,再调用 UserInfo 获取用户身份,即可完成「使用本站账号登录」。
V2 服务端点(全部位于 /v2/ 前缀下):
Issuer https://auth.401522.xyz Authorization Endpoint https://auth.401522.xyz/v2/authorize.php Token Endpoint https://auth.401522.xyz/v2/token.php UserInfo Endpoint https://auth.401522.xyz/v2/userinfo.php User Endpoint https://auth.401522.xyz/v2/user.php Refresh Endpoint https://auth.401522.xyz/v2/refresh.php Revocation Endpoint https://auth.401522.xyz/v2/revoke.php Introspection Endpoint https://auth.401522.xyz/v2/introspect.php API KEY Endpoint https://auth.401522.xyz/v2/keys.php Verify Endpoint https://auth.401522.xyz/v2/verify.php Discovery https://auth.401522.xyz/v2/.well-known/openid-configuration Asset Links https://auth.401522.xyz/.well-known/assetlinks.json
V1 → V2 迁移
V2 是 V1 的超集,迁移成本极低。核心变化只有三点:
| 项目 | V1 | V2 |
|---|---|---|
| 接口路径 | /token.php、/api/userinfo.php … | /v2/token.php、/v2/userinfo.php … |
| 请求参数 | 完全一致,无需修改 | |
| 成功响应字段 | 完全一致(V2 额外附带 api_version 与 request_id) | |
| 错误响应 | 仅 error + error_description | 额外提供 error_code(细粒度业务码)、error_title、http_status |
| API KEY | 仅支持「有效 / 无效」 | 支持轮换与有效期,失效原因可区分 |
最小改动示例:
// 迁移前(V1) POST https://auth.401522.xyz/token.php // 迁移后(V2) POST https://auth.401522.xyz/v2/token.php
快速开始
- 登录控制台,在「我的应用」中创建应用,选择客户端类型(Web 应用 / 移动应用 / SPA)。
- 填写回调地址。移动端可填自定义 Scheme,例如
myapp://oauth/callback;选择「移动应用」时必须填写 Android 包名。 - 保存后获得
client_id与client_secret(公共客户端可只使用 client_id + PKCE)。 - 按下方流程引导用户授权,并用授权码换取令牌。
Web 授权码流程
1. 引导用户授权
GET https://auth.401522.xyz/v2/authorize.php ?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=https%3A%2F%2Fyour-site.com%2Fcallback &scope=openid%20profile%20email &state=RANDOM_STATE
2. 回调换取令牌
POST https://auth.401522.xyz/v2/token.php Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=RETURNED_CODE &redirect_uri=https://your-site.com/callback &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET
也支持 Authorization: Basic base64(client_id:client_secret) 的机密客户端认证方式。
3. 获取用户信息
GET https://auth.401522.xyz/v2/userinfo.php Authorization: Bearer ACCESS_TOKEN
PKCE 接入(移动端 / SPA 必选)
移动应用与单页应用无法安全保存 client_secret,必须使用 PKCE(RFC 7636)。在创建应用时将客户端类型设为「移动应用」或「SPA」,服务端会强制校验 code_challenge。
// 1. 生成随机 verifier(43-128 位) verifier = base64url(random(32 bytes)) // 2. 计算 challenge challenge = base64url(sha256(verifier)) // 3. 授权请求附带 GET /v2/authorize.php?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=myapp://oauth/callback &code_challenge=CHALLENGE &code_challenge_method=S256 &state=STATE // 4. 换取令牌时回传 verifier POST /v2/token.php grant_type=authorization_code&code=CODE &client_id=YOUR_CLIENT_ID &code_verifier=VERIFIER &redirect_uri=myapp://oauth/callback
Token 端点同时支持 application/x-www-form-urlencoded 与 application/json 请求体,并返回 CORS 头,可直接在 App 原生网络库中调用。
Android 客户端接入
回调地址的三种写法
- 自定义 Scheme:
myapp://oauth/callback,最简单,在AndroidManifest.xml中声明 intent-filter 即可。 - App Links(推荐):
https://auth.401522.xyz/android/callback,通过 assetlinks.json 校验后可直接唤端,无选择弹窗。 - intent://:
intent://oauth/callback#Intent;scheme=myapp;package=com.example.app;end,可精确指定 package。
Manifest 示例
唤起流程
授权成功后,服务端不会直接 302 到自定义 Scheme(浏览器会拦截),而是先跳到站内中间页 /app_redirect.php,由页面通过 JS 唤起 App,并提供「打开应用」按钮兜底。App 只需处理回调 URL 中的 code 与 state。
myapp://oauth/callback?code=XXXX&state=YYYY
建议使用 Custom Tabs(androidx.browser)打开授权页,以共享浏览器登录态:
CustomTabsIntent.Builder()
.build()
.launchUrl(context, Uri.parse(authUrl));
App Links 与 assetlinks.json
在应用编辑页填写 Android 包名与签名 SHA-256 指纹后,本站会自动生成数字资产关联文件:
GET https://auth.401522.xyz/.well-known/assetlinks.json
内容形如:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["AA:BB:CC:..."]
}
}]
获取指纹:keytool -list -v -keystore your.jks -alias your_alias。配置完成并重新安装 App 后,系统会自动校验并直接以你的应用打开 https 链接。
网页唤起安卓验证
除「标准授权码」外,本站还提供一条网页 → intent → 安卓客户端 → 验证 → 回传网页的完整链路,适合「点击按钮直接用本站账号免密登录」这类场景。
整体流程
① 网页 POST /v2/verify.php action=ticket
→ 得到 ticket(一次性,5 分钟有效)
② 网页 用 intent:// 或 App Links 唤起安卓客户端,携带 ticket
③ 客户端 用 Custom Tabs 打开 /v2/authorize.php 完成登录授权
→ 拿到 code → 换 access_token
④ 客户端 POST /v2/verify.php action=verify ticket + access_token
→ 服务端生成 assertion(身份断言,120 秒有效)
⑤ 网页 GET /v2/verify.php action=status 轮询拿到 assertion
⑥ 网页后端 POST /v2/verify.php action=check 校验 assertion
→ 得到用户身份(sub / username / email)
唤起协议
# 自定义 Scheme(无需域名校验) intent://oauth/verify?S.ticket=TICKET#Intent; scheme=fusionoauth;package=xyz.uoxvx.fusionoauth;end # App Links(推荐,系统校验通过后免选择弹窗) https://auth.401522.xyz/android/verify.php?ticket=TICKET
安卓客户端源码见交付包中的 android-client/ 目录(Kotlin + Gradle)。详细的接口参数见下方 安卓唤起验证端点 一节。
Web 调用官方客户端登录 推荐
网页端与安卓客户端是两套独立前端,各自持有独立登录态、互不内嵌。当网页需要登录时,可发起一次标准 OAuth 授权码 + PKCE 流程,把「用户认证」这一步交给已登录的官方安卓客户端确认,随后网页在自己上下文完成同意页、授权码与令牌兑换。因为发起方是平台内置客户端,授权页会显示「官方」标记,但流程本身与普通 OAuth 完全一致。
整体流程
① 网页 GET /oauth_login.php?redirect=/dashboard.php
→ 生成 state + PKCE,302 到 /v2/authorize.php(prompt=app)
② 授权端点 未登录且为官方客户端 → 创建一次性授权请求,渲染等待页
等待页用 intent:// 唤起官方客户端,浏览器同时轮询状态端点
③ 客户端 用本地登录态(Bearer mobile access_token)确认请求
④ 网页 GET /app_auth_status.php?request=... 轮询到 approved
→ 在浏览器会话建立 Web 登录态,回跳不带 prompt=app 的授权端点
⑤ 网页 显示普通同意页(带「官方」标记)→ 用户同意
→ 302 回 /oauth_callback.php?code=...&state=...
⑥ 网页后端 用 code + code_verifier 兑换标准 access_token / id_token
→ 写入 Web 会话,登录完成
端点一览
| 端点 | 方法 | 作用 |
|---|---|---|
/oauth_login.php | GET | 网页端发起登录(RP 入口),生成 state 与 PKCE |
/v2/authorize.php | GET | 标准授权端点;prompt=app 且为官方客户端时进入等待页 |
/app_auth_status.php | GET | 浏览器轮询;approved 时建立 Web 会话并返回回跳地址 |
/api/mobile/authorize.php | POST | 官方客户端确认 / 拒绝请求,需 Authorization: Bearer mat_… |
/android/authorize.php | GET | App Links 落地点;安卓 UA 下 302 到 intent:// |
/oauth_callback.php | GET | 标准回调,服务端用 code + PKCE 兑换令牌 |
关键参数
| 参数 | 位置 | 说明 |
|---|---|---|
prompt=app | 授权端点 | 仅官方网页客户端可用;第三方客户端即使携带,也仍被导向密码登录页 |
code_challengecode_challenge_method=S256 | 授权端点 | PKCE,全流程强制 |
state / nonce | 授权端点 | CSRF 与重放防护,回调时原样校验 |
request | 轮询 / 确认 | 一次性授权请求 ID,5 分钟过期,绑定 client_id、redirect_uri、state 与 PKCE |
approve | 客户端确认 | true 确认、false 拒绝;同一请求只能处理一次 |
official | 响应字段 | 布尔值,标识该应用 / 授权记录属于平台官方客户端 |
唤起协议
# 自定义 Scheme(等待页自动生成) intent://oauth/authorize?S.request=REQUEST_ID#Intent; scheme=fusionoauth;package=xyz.uoxvx.fusionoauth;end # App Links 落地点(安卓 UA 下由服务端 302 到上面的 intent) https://auth.401522.xyz/android/authorize.php?request=REQUEST_ID
POST /v2/token.php
#颁发令牌对。支持两种 grant_type:authorization_code(用授权码换令牌)与 refresh_token(用刷新令牌换新令牌对)。refresh_token 为严格一次性凭据,刷新后旧令牌立即失效。
Authorization: Basic base64(client_id:client_secret),或在请求体携带 client_id + client_secret。公共客户端(移动应用 / SPA):仅需
client_id,但必须携带 code_verifier。https://auth.401522.xyz/v2/token.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
grant_typeBODY | string | 必填 | 授权类型。可选值:authorization_code、refresh_token |
codeBODY | string | 条件必填 | 授权码。grant_type=authorization_code 时必填 |
redirect_uriBODY | string | 条件必填 | 必须与授权时使用的完全一致。grant_type=authorization_code 时若在授权请求中携带过,则此处必填 |
code_verifierBODY | string | 条件必填 | PKCE 校验串。公共客户端必填,需为 43~128 位 [A-Za-z0-9-._~] 字符 |
client_idBODY | string | 必填 | 应用 ID |
client_secretBODY | string | 条件必填 | 应用密钥。机密客户端必填;公共客户端不可携带 |
refresh_tokenBODY | string | 条件必填 | 刷新令牌。grant_type=refresh_token 时必填 |
请求示例
POST https://auth.401522.xyz/v2/token.php Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=AUTHORIZATION_CODE &redirect_uri=https://your-site.com/callback &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET &code_verifier=YOUR_CODE_VERIFIER
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"access_token": "a1b2c3d4e5f6…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "r1e2f3a4b5c6…",
"scope": "openid profile email",
"id_token": "eyJhbGciOiJIUzI1NiIs…"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2,用于区分 V1 响应 |
request_id | string | 本次请求的追踪 ID,排查问题时请一并提供 |
access_token | string | 访问令牌,放入 Authorization: Bearer 请求头使用 |
token_type | string | 令牌类型,固定为 Bearer |
expires_in | integer | 访问令牌有效期(秒),默认 3600 |
refresh_token | string | 刷新令牌,用于换取新的令牌对 |
scope | string | 实际授予的权限范围 |
id_token | string | ID Token(JWT)。仅当 scope 含 openid 时返回 |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 client_id、grant_type、code 或 refresh_token 等必要参数 |
| unsupported_grant_type | 400 | grant_type 不是 authorization_code 或 refresh_token |
| client_secret_invalid | 401 | client_secret 不正确 |
| client_pending_review | 403 | 应用尚未通过管理员审核 |
| client_banned | 403 | 应用已被封禁 |
| code_invalid | 400 | 授权码不存在 |
| code_expired | 400 | 授权码已过期(有效期 10 分钟) |
| code_used | 400 | 授权码已被使用,每个授权码只能兑换一次 |
| redirect_uri_mismatch | 400 | redirect_uri 与授权时不一致 |
| pkce_required | 400 | 公共客户端未携带 code_verifier |
| pkce_failed | 400 | code_verifier 缺失、格式非法或摘要不匹配 |
| refresh_token_invalid | 400 | refresh_token 不存在 |
| refresh_token_expired | 400 | refresh_token 已过期 |
| refresh_token_used | 400 | refresh_token 已被使用,请重新授权 |
| user_banned | 403 | 用户账号已被封禁 |
| user_not_approved | 403 | 用户账号尚未通过审核 |
GET /v2/userinfo.php
#OIDC 标准 UserInfo 端点。根据访问令牌返回用户身份信息,返回字段受 scope 控制。用户被封禁时返回 user_banned。
Authorization: Bearer ACCESS_TOKEN(也可用 access_token 查询参数传递,不推荐)。https://auth.401522.xyz/v2/userinfo.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
access_tokenHEADER | string | 可选 | 访问令牌,推荐通过 Authorization: Bearer 请求头传递 |
请求示例
GET https://auth.401522.xyz/v2/userinfo.php Authorization: Bearer ACCESS_TOKEN
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"sub": "1",
"name": "username",
"preferred_username": "username",
"email": "user@example.com",
"email_verified": true,
"role": "user",
"created_at": "2025-01-01 10:00:00"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2 |
request_id | string | 本次请求的追踪 ID |
sub | string | 用户唯一标识(用户 ID 的字符串形式) |
name | string | 用户名。scope 含 openid / profile / basic 时返回 |
preferred_username | string | 首选用户名。同上 scope 条件下返回 |
role | string | 用户角色。同上 scope 条件下返回 |
created_at | string | 账号创建时间。同上 scope 条件下返回 |
email | string | 邮箱地址。scope 含 email 时返回 |
email_verified | boolean | 邮箱是否已验证。scope 含 email 时返回 |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| invalid_token | 401 | 访问令牌不存在或格式错误 |
| token_expired | 401 | 访问令牌已过期,请用 refresh_token 刷新 |
| token_revoked | 401 | 访问令牌已被撤销,请重新授权 |
| user_banned | 403 | 用户账号已被封禁 |
| user_not_approved | 403 | 用户账号尚未通过审核 |
GET /v2/user.php
#供服务端后台使用的应用级接口。与 UserInfo 不同,本接口必须同时携带 API KEY 与访问令牌,且令牌必须属于同一个 client_id,返回字段固定完整(不受 scope 控制)。
client_id + api_key,请求头携带 Authorization: Bearer ACCESS_TOKEN。https://auth.401522.xyz/v2/user.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
client_idQUERY | string | 必填 | 应用 ID |
api_keyQUERY | string | 必填 | 应用级 API KEY,可在控制台「我的应用 → 编辑应用」查看 |
access_tokenHEADER | string | 必填 | 访问令牌,且必须属于该 client_id |
请求示例
GET https://auth.401522.xyz/v2/user.php?client_id=YOUR_CLIENT_ID&api_key=YOUR_API_KEY Authorization: Bearer ACCESS_TOKEN
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"id": 1,
"sub": "1",
"username": "username",
"name": "username",
"email": "user@example.com",
"email_verified": true,
"role": "user",
"created_at": "2025-01-01 10:00:00"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2 |
request_id | string | 本次请求的追踪 ID |
id | integer | 用户数字 ID |
sub | string | 用户唯一标识(字符串形式) |
username | string | 用户名 |
name | string | 显示名 |
email | string | 邮箱地址 |
email_verified | boolean | 邮箱是否已验证 |
role | string | 用户角色 |
created_at | string | 账号创建时间 |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 client_id 参数 |
| api_key_missing | 401 | 缺少 api_key 参数 |
| api_key_invalid | 401 | API KEY 不正确 |
| api_key_expired | 401 | API KEY 已过期,请在控制台重新生成 |
| api_key_revoked | 401 | API KEY 已被轮换或作废,请使用新 KEY |
| api_key_mismatch | 401 | API KEY 与 client_id 不匹配 |
| client_pending_review | 403 | 应用尚未通过管理员审核 |
| client_banned | 403 | 应用已被封禁 |
| invalid_token | 401 | 访问令牌无效,或不属于该 client_id |
| user_banned | 403 | 用户账号已被封禁 |
POST /v2/refresh.php
#使用 refresh_token 换取新的令牌对。严格一次性轮换:刷新成功后旧 refresh_token 与旧 access_token 立即失效,若重复使用将返回 refresh_token_used。
client_id + client_secret(机密客户端),或 client_id + api_key(应用级调用),或仅 client_id(公共客户端)。也支持 Authorization: Basic。https://auth.401522.xyz/v2/refresh.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
client_idBODY | string | 必填 | 应用 ID |
refresh_tokenBODY | string | 必填 | 要刷新的 refresh_token |
client_secretBODY | string | 可选 | 应用密钥。机密客户端必填(若未携带 api_key) |
api_keyBODY | string | 可选 | 应用级 API KEY,与 client_secret 二选一 |
请求示例
POST https://auth.401522.xyz/v2/refresh.php Content-Type: application/x-www-form-urlencoded grant_type=refresh_token &refresh_token=YOUR_REFRESH_TOKEN &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"access_token": "n1e2w3t4k5j6…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "n1r2e3f4r5e6…",
"scope": "openid profile email"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2 |
request_id | string | 本次请求的追踪 ID |
access_token | string | 新的访问令牌 |
token_type | string | 固定为 Bearer |
expires_in | integer | 访问令牌有效期(秒) |
refresh_token | string | 新的刷新令牌,请立即替换本地副本 |
scope | string | 实际授予的权限范围 |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 client_id 或 refresh_token |
| client_secret_invalid | 401 | client_secret 不正确 |
| api_key_expired | 401 | API KEY 已过期 |
| api_key_revoked | 401 | API KEY 已被轮换或作废 |
| refresh_token_invalid | 400 | refresh_token 不存在 |
| refresh_token_expired | 400 | refresh_token 已过期,请重新授权 |
| refresh_token_used | 400 | refresh_token 已被使用(一次性凭据),请重新授权 |
| invalid_grant | 400 | refresh_token 与 client_id 不匹配 |
| user_banned | 403 | 用户账号已被封禁 |
POST /v2/revoke.php
#撤销访问令牌或刷新令牌(RFC 7009)。符合规范:无论令牌是否存在、是否已被撤销,均返回 200,通过响应字段区分结果。
client_id + client_secret,或 client_id + api_key。也支持 Authorization: Basic。https://auth.401522.xyz/v2/revoke.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
tokenBODY | string | 必填 | 要撤销的访问令牌或刷新令牌 |
client_idBODY | string | 必填 | 应用 ID |
client_secretBODY | string | 可选 | 应用密钥。机密客户端必填(若未携带 api_key) |
api_keyBODY | string | 可选 | 应用级 API KEY,与 client_secret 二选一 |
请求示例
POST https://auth.401522.xyz/v2/revoke.php Content-Type: application/x-www-form-urlencoded token=TOKEN_TO_REVOKE &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"revoked": true,
"changed": true,
"status": "revoked"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2 |
request_id | string | 本次请求的追踪 ID |
revoked | boolean | 该令牌当前是否处于失效状态(不存在时为 false) |
changed | boolean | 本次请求是否实际执行了撤销操作 |
status | string | 撤销结果:revoked(本次撤销成功)/ already_revoked(此前已撤销)/ not_found(令牌不属于该应用) |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 token 或 client_id |
| client_secret_invalid | 401 | client_secret 不正确 |
| api_key_invalid | 401 | API KEY 不正确 |
| client_banned | 403 | 应用已被封禁 |
POST /v2/introspect.php
#查询令牌当前状态(RFC 7662)。同时支持访问令牌与刷新令牌;令牌不存在时返回 active: false 而非报错。
client_id + client_secret,或 client_id + api_key。也支持 Authorization: Basic。https://auth.401522.xyz/v2/introspect.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
tokenBODY | string | 必填 | 要查询的访问令牌或刷新令牌 |
client_idBODY | string | 必填 | 应用 ID |
client_secretBODY | string | 可选 | 应用密钥。机密客户端必填(若未携带 api_key) |
api_keyBODY | string | 可选 | 应用级 API KEY,与 client_secret 二选一 |
请求示例
POST https://auth.401522.xyz/v2/introspect.php Content-Type: application/x-www-form-urlencoded token=TOKEN_TO_INTROSPECT &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"active": true,
"scope": "openid profile email",
"client_id": "fusion_xxx",
"username": "username",
"token_type": "Bearer",
"exp": 1735660800,
"iat": 1735574400,
"sub": "1",
"status": "active"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2 |
request_id | string | 本次请求的追踪 ID |
active | boolean | 令牌当前是否有效 |
scope | string | 令牌携带的权限范围 |
client_id | string | 令牌所属应用 |
username | string | 令牌所属用户名(仅访问令牌返回) |
token_type | string | 令牌类型:Bearer 或 refresh_token |
exp | integer | 过期时间(Unix 时间戳) |
iat | integer | 签发时间(Unix 时间戳) |
sub | string | 用户唯一标识 |
status | string | 令牌状态:active / revoked / expired / not_found |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 token 或 client_id |
| client_secret_invalid | 401 | client_secret 不正确 |
| api_key_invalid | 401 | API KEY 不正确 |
| client_banned | 403 | 应用已被封禁 |
GETPOST /v2/keys.php
#查询 API KEY 状态、轮换(生成新 KEY,旧 KEY 立即失效)或作废(不生成新 KEY)。轮换时可选设置新 KEY 的有效期(天)。
client_id + api_key(自身凭据),或 client_id + client_secret(机密客户端可在服务端执行轮换)。也支持 Authorization: Basic。https://auth.401522.xyz/v2/keys.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
client_idQUERY | string | 必填 | 应用 ID |
api_keyQUERY | string | 条件必填 | API KEY。与 client_secret 二选一 |
client_secretQUERY | string | 条件必填 | 应用密钥。与 api_key 二选一 |
actionBODY | string | 可选 | POST 时的操作:rotate(轮换)/ revoke(作废)。缺省为 rotate默认值 rotate |
ttl_daysBODY | integer | 可选 | 新 KEY 的有效期(天)。0 或不传表示永不过期 |
请求示例
# 查询状态 GET https://auth.401522.xyz/v2/keys.php?client_id=YOUR_CLIENT_ID&api_key=YOUR_API_KEY # 轮换(30 天后过期) POST https://auth.401522.xyz/v2/keys.php?client_id=YOUR_CLIENT_ID&api_key=YOUR_API_KEY Content-Type: application/x-www-form-urlencoded action=rotate&ttl_days=30 # 仅作废 POST https://auth.401522.xyz/v2/keys.php?client_id=YOUR_CLIENT_ID&api_key=YOUR_API_KEY Content-Type: application/x-www-form-urlencoded action=revoke
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"rotated": true,
"api_key": "sk_NEW_KEY_ONLY_SHOWN_ONCE",
"api_key_masked": "sk_9f2c…7b41",
"previous_key_revoked_at": 1730000000,
"expires_at": 1732592000,
"expires_in": 2592000,
"notice": "新 API KEY 仅在本次响应中返回,请立即保存。旧 API KEY 已立即失效。"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2 |
request_id | string | 本次请求的追踪 ID |
rotated | boolean | (轮换响应)是否已轮换 |
api_key | string | (轮换响应)新 KEY,仅本次返回 |
api_key_masked | string | 掩码后的 KEY,用于展示 |
previous_key_revoked_at | integer | (轮换响应)旧 KEY 作废时间戳 |
expires_at | integer | 到期时间戳;null 表示永不过期 |
expires_in | integer | 剩余有效秒数 |
notice | string | 操作提示文案 |
status | string | (查询响应)KEY 状态:active / expired |
client_name | string | (查询响应)应用名称 |
created_at | string | (查询响应)KEY 创建时间 |
ttl_days | integer | (查询响应)当前有效期设置(天) |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| api_key_missing | 401 | 缺少 api_key 或 client_secret |
| api_key_invalid | 401 | API KEY 不正确 |
| api_key_expired | 401 | API KEY 已过期 |
| api_key_revoked | 401 | API KEY 已被轮换或作废 |
| api_key_mismatch | 401 | API KEY 与 client_id 不匹配 |
| client_banned | 403 | 应用已被封禁 |
| unsupported_method | 405 | 请求方法不是 GET 或 POST |
| invalid_request | 400 | action 不在 rotate / revoke 范围内,或该应用已无可用 KEY |
GETPOST /v2/verify.php
#支撑「网页 → intent → 安卓客户端 → 验证 → 回传网页」链路。共 4 个 action:ticket 申请一次性票据、verify 客户端提交令牌、status 网页轮询结果、check 网页服务端校验断言。
ticket / verify / check 需携带 client_id;verify 另需客户端持有的 access_token;status 需携带 ticket。https://auth.401522.xyz/v2/verify.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
actionBODY | string | 必填 | 操作类型:ticket / verify / status / check |
client_idBODY | string | 必填 | 应用 ID |
redirect_uriBODY | string | 条件必填 | 发起方网页回调地址,必须在该应用登记的白名单内。action=ticket 时必填 |
stateBODY | string | 可选 | 防 CSRF 随机串,验证成功后随断言回传 |
nonceBODY | string | 可选 | 防重放随机串 |
scopeBODY | string | 可选 | 请求的权限范围 |
ticketBODY | string | 条件必填 | 一次性票据。action=verify / status 时必填 |
access_tokenBODY | string | 条件必填 | 客户端通过授权流程获得的访问令牌。action=verify 时必填 |
assertionBODY | string | 条件必填 | 服务端签发的身份断言。action=check 时必填 |
请求示例
# ① 网页申请一次性票据 POST https://auth.401522.xyz/v2/verify.php Content-Type: application/x-www-form-urlencoded action=ticket&client_id=YOUR_CLIENT_ID &redirect_uri=https://your-site.com/verify-callback &state=RANDOM_STATE&nonce=RANDOM_NONCE # ② 唤起安卓客户端(网页侧发起) intent://oauth/verify?S.ticket=TICKET#Intent; scheme=fusionoauth;package=xyz.uoxvx.fusionoauth;end # ③ 客户端提交令牌完成验证 POST https://auth.401522.xyz/v2/verify.php Content-Type: application/x-www-form-urlencoded action=verify&client_id=YOUR_CLIENT_ID &ticket=TICKET&access_token=ACCESS_TOKEN # ④ 网页服务端校验断言 POST https://auth.401522.xyz/v2/verify.php Content-Type: application/x-www-form-urlencoded action=check&client_id=YOUR_CLIENT_ID &assertion=ASSERTION_FROM_STATUS
响应示例
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"ticket": "9f3c…7b41",
"expires_in": 300,
"intent_url": "intent://oauth/verify?S.ticket=9f3c…#Intent;scheme=fusionoauth;package=xyz.uoxvx.fusionoauth;end",
"app_links_url": "https://your-host/android/verify.php?ticket=9f3c…"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
api_version | string | 固定为 v2 |
request_id | string | 本次请求的追踪 ID |
ticket | string | 一次性票据,有效期 5 分钟,成功验证后立即作废 |
expires_in | integer | 票据剩余有效秒数 |
intent_url | string | 唤起安卓客户端的 intent URL |
app_links_url | string | App Links 形式的唤起地址(推荐,系统校验通过后免选择弹窗) |
verified | boolean | (verify / status 响应)验证是否已完成 |
assertion | string | (status 响应)身份断言,供网页服务端调用 action=check 校验 |
sub | string | (check 响应)用户唯一标识 |
username | string | (check 响应)用户名 |
email | string | (check 响应)邮箱地址 |
client_id(audience)与 state,网页服务端必须自行校验 state 并通过 action=check 换取用户身份,切勿直接信任前端传来的用户信息。错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 action、client_id 等必要参数 |
| invalid_request | 400 | action 取值不在支持范围内 |
| ticket_invalid | 400 | 票据不存在或已被消费 |
| ticket_expired | 400 | 票据已过期(有效期 5 分钟) |
| ticket_consumed | 400 | 票据已被使用,请重新申请 |
| assertion_invalid | 400 | 断言签名不匹配、已过期或 audience 不符 |
| redirect_uri_mismatch | 400 | redirect_uri 未在应用登记的白名单内 |
| invalid_token | 401 | 客户端提交的 access_token 无效 |
| client_banned | 403 | 应用已被封禁 |
| user_banned | 403 | 用户账号已被封禁 |
GET /api/mobile/captcha.php
#获取无状态图形验证码。返回签名令牌与图片,登录时需一并回传。令牌一次性使用,5 分钟过期。
https://auth.401522.xyz/api/mobile/captcha.php请求示例
GET https://auth.401522.xyz/api/mobile/captcha.php
响应示例
{
"api_version": "mobile",
"captcha_token": "eyJjIjoi…",
"image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0…",
"svg": "<svg xmlns=…</svg>",
"expires_in": 300
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
captcha_token | string | 签名令牌。载荷只含随机盐与 HMAC,不含明文答案 |
image | string | 验证码图片的 Data URI(SVG) |
svg | string | 验证码图片的 SVG 源码 |
expires_in | integer | 有效期(秒),固定 300 |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| unsupported_method | 405 | 请求方法不是 GET |
POST /api/mobile/login.php
#使用用户名或邮箱 + 密码换取移动端令牌对。成功后令牌可用于调用全部移动端接口。
https://auth.401522.xyz/api/mobile/login.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
accountBODY | string | 必填 | 用户名或邮箱 |
passwordBODY | string | 必填 | 登录密码 |
captcha_tokenBODY | string | 可选 | 图形验证码令牌(平台开启人机验证时必填) |
captchaBODY | string | 可选 | 用户输入的验证码字符 |
deviceBODY | string | 可选 | 设备标识,写入登录日志便于识别 |
请求示例
POST https://auth.401522.xyz/api/mobile/login.php
Content-Type: application/json
{
"account": "yourname",
"password": "your-password",
"captcha_token": "eyJjIjoi…",
"captcha": "A7K2",
"device": "android/34 Pixel 8"
}响应示例
{
"api_version": "mobile",
"access_token": "mat_9f3c7b41…",
"refresh_token": "mrt_2e8d4a10…",
"token_type": "Bearer",
"expires_in": 2592000,
"expires_at": 1793548800,
"user": {
"id": 12,
"username": "yourname",
"email": "you@example.com",
"email_verified": true,
"role": "user",
"created_at": "2026-01-02 10:30:00",
"is_admin": false
}
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
access_token | string | 访问令牌,后续接口通过 Authorization: Bearer 携带 |
refresh_token | string | 刷新令牌,用于换取新的访问令牌 |
token_type | string | 固定为 Bearer |
expires_in | integer | 访问令牌有效期(秒),固定 30 天 |
expires_at | integer | 访问令牌过期时间戳 |
user | object | 当前账号信息 |
user.id | integer | 账号 ID |
user.username | string | 用户名 |
user.email | string | 邮箱地址 |
user.email_verified | boolean | 邮箱是否已验证 |
user.role | string | 账号角色(user / admin) |
user.is_admin | boolean | 是否管理员(移动端不开放管理功能) |
rate_limited。移动端令牌独立于 OAuth access_token,不会出现在「我的授权」列表中。错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 account 或 password |
| captcha_required | 400 | 平台开启了人机验证但未提交验证码 |
| captcha_invalid | 400 | 验证码错误、已被使用或令牌签名不合法 |
| captcha_expired | 400 | 验证码已过期(有效期 5 分钟) |
| invalid_credentials | 401 | 账号或密码错误(不区分具体原因,避免账号枚举) |
| account_disabled | 403 | 账号已被停用 |
| rate_limited | 429 | 尝试过于频繁(同 IP 20 次/分钟,同账号 10 次/分钟) |
POST /api/mobile/refresh.php
#使用刷新令牌换取新的访问令牌。旧访问令牌立即失效。
https://auth.401522.xyz/api/mobile/refresh.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
refresh_tokenBODY | string | 必填 | 登录时获得的刷新令牌 |
请求示例
POST https://auth.401522.xyz/api/mobile/refresh.php
Content-Type: application/json
{
"refresh_token": "mrt_2e8d4a10…"
}响应示例
{
"api_version": "mobile",
"access_token": "mat_c8a0f180…",
"token_type": "Bearer",
"expires_in": 2592000,
"expires_at": 1793548800
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
access_token | string | 新的访问令牌 |
token_type | string | 固定为 Bearer |
expires_in | integer | 访问令牌有效期(秒) |
expires_at | integer | 过期时间戳 |
错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 refresh_token |
| refresh_token_invalid | 400 | 刷新令牌无效或已被注销 |
| refresh_token_expired | 400 | 刷新令牌已过期,需重新登录 |
GET /api/mobile/dashboard.php
#一次获取账号信息、统计数字、系统公告与最近应用,供客户端控制台首页渲染。
https://auth.401522.xyz/api/mobile/dashboard.php请求示例
GET https://auth.401522.xyz/api/mobile/dashboard.php Authorization: Bearer mat_9f3c7b41…
响应示例
{
"api_version": "mobile",
"user": {
"id": 12, "username": "yourname", "email": "you@example.com",
"email_verified": true, "role": "user",
"created_at": "2026-01-02 10:30:00", "is_admin": false
},
"stats": {
"app_count": 3, "authorization_count": 12,
"active_count": 9, "revoked_count": 3
},
"apps": [ { "id": 1, "name": "我的应用", "client_id": "fusion_…", "status_label": "正常" } ],
"announcements": [
{ "title": "系统维护通知", "content": "本周六 02:00-04:00 进行维护。", "created_at": "2026-10-20 09:00:00" }
]
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
user | object | 当前账号信息 |
stats | object | 统计数字 |
stats.app_count | integer | 我的应用数量 |
stats.authorization_count | integer | 授权记录总数 |
stats.active_count | integer | 当前有效的授权数 |
stats.revoked_count | integer | 已过期或已撤销的授权数 |
apps | array | 最近 5 个应用概要 |
announcements | array | 系统公告(最多 5 条) |
/api/mobile/refresh.php 续期,失败再引导用户重新登录。错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| invalid_token | 401 | 令牌不存在 |
| token_expired | 401 | 令牌已过期,请刷新或重新登录 |
| token_revoked | 401 | 令牌已被注销 |
| account_disabled | 403 | 账号已被停用 |
GETPOST /api/mobile/apps.php
#列出、新建、修改、轮换密钥、作废密钥与删除自己的应用。列表只返回掩码后的 API KEY。
https://auth.401522.xyz/api/mobile/apps.php请求参数
| 名称 | 类型 | 属性 | 说明 |
|---|---|---|---|
actionBODY | string | 可选 | 操作类型:list / create / update / rotate_key / revoke_key / delete,GET 时默认为 list |
idBODY | integer | 可选 | 应用 ID(除 list 外均需要) |
nameBODY | string | 可选 | 应用名称(create / update 必填) |
client_typeBODY | string | 可选 | 应用类型:web / spa / app |
redirect_urisBODY | string | 可选 | 回调地址,多个用换行或逗号分隔 |
homepage_urlBODY | string | 可选 | 主页地址 |
descriptionBODY | string | 可选 | 应用描述 |
app_packageBODY | string | 可选 | Android 包名(client_type=app 时必填) |
app_sha256BODY | string | 可选 | 证书 SHA-256 指纹,用于 App Links 校验 |
ttl_daysBODY | integer | 可选 | 新密钥有效期(天),0 表示永久 |
请求示例
POST https://auth.401522.xyz/api/mobile/apps.php
Authorization: Bearer mat_9f3c7b41…
Content-Type: application/json
{
"action": "create",
"name": "我的移动应用",
"client_type": "app",
"redirect_uris": "fusionoauth://oauth/callback",
"app_package": "com.example.myapp"
}响应示例
{
"api_version": "mobile",
"app": {
"id": 5,
"client_id": "fusion_Ll64HxtbD6yk2w352v4sw",
"name": "我的移动应用",
"client_type": "app",
"client_type_label": "移动应用",
"redirect_uris": ["fusionoauth://oauth/callback"],
"app_package": "com.example.myapp",
"api_key_masked": "sk_42933…f06b",
"has_api_key": true,
"status": "pending",
"status_label": "待审核",
"created_at": "2026-11-01 09:30:00"
},
"client_secret": "…",
"api_key": "sk_429338a3a…",
"notice": "应用创建成功,等待管理员审核通过后方可调用 API。…"
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
apps | array | (list 响应)应用列表 |
total | integer | (list 响应)应用总数 |
app | object | (create / update / 密钥操作响应)应用信息 |
app.api_key_masked | string | 掩码后的 API KEY,形如 sk_42933…f06b |
app.has_api_key | boolean | 是否已设置 API KEY |
app.status_label | string | 状态中文名:正常 / 待审核 / 已禁用 |
client_secret | string | (create 响应)明文 Client Secret,仅此一次返回 |
api_key | string | (create / rotate_key 响应)明文 API KEY,仅此一次返回 |
notice | string | 操作结果提示 |
deleted | boolean | (delete 响应)是否删除成功 |
api_key 不会再次出现在列表中。轮换后旧 KEY 立即失效,使用旧 KEY 的调用会返回 api_key_revoked。所有操作严格限定在当前账号名下,无法操作他人应用。错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| missing_parameter | 400 | 缺少 id 等必要参数 |
| invalid_request | 400 | 参数校验失败(如回调地址非法、移动应用未填包名) |
| app_not_found | 404 | 应用不存在或不属于当前账号 |
| invalid_token | 401 | 令牌无效或已过期 |
POST /api/mobile/logout.php
#注销当前移动端令牌,使其立即失效。
https://auth.401522.xyz/api/mobile/logout.php请求示例
POST https://auth.401522.xyz/api/mobile/logout.php Authorization: Bearer mat_9f3c7b41…
响应示例
{
"api_version": "mobile",
"revoked": true
}响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
revoked | boolean | 是否已注销 |
token_revoked。错误响应
| error_code | HTTP | 含义与处理建议 |
|---|---|---|
| unsupported_method | 405 | 请求方法不是 POST |
V2 错误码
V2 错误响应采用双层错误码结构:error 保持 OAuth2 标准语义(你的既有分支逻辑无需修改),error_code 提供细粒度业务原因(用于精确定位问题)。
{
"api_version": "v2",
"request_id": "req_1a2b3c4d5e6f7a8b",
"error": "invalid_client",
"error_code": "client_banned",
"error_title": "应用已被封禁",
"error_description": "应用「我的应用」已被封禁,当前状态:已封禁。无法调用 API,如有疑问请联系平台管理员。",
"http_status": 403,
"timestamp": 1730000000,
"error_uri": "https://auth.401522.xyz/docs.php#v2-errors"
}
应用状态相关
| error_code | HTTP | 标准 error | 含义与处理建议 |
|---|---|---|---|
| client_not_found | 401 | invalid_client |
client_id 不存在,应用可能已被删除。检查应用配置。 |
| client_pending_review | 403 | invalid_client |
应用尚未通过管理员审核,暂时无法调用 API。等待审核通过后重试。 |
| client_banned | 403 | invalid_client |
应用已被封禁(状态为 disabled / banned)。请联系平台管理员。 |
| client_disabled | 403 | invalid_client |
应用已被停用,请检查应用状态或联系管理员恢复。 |
| client_secret_invalid | 401 | invalid_client |
client_secret 不正确,请检查应用配置。 |
| unauthorized_client | 403 | unauthorized_client |
该客户端无权执行此操作(如用 API KEY 访问不支持的端点)。 |
API KEY 相关
| error_code | HTTP | 标准 error | 含义与处理建议 |
|---|---|---|---|
| api_key_missing | 401 | invalid_client |
缺少 api_key 参数,请在请求中携带应用级 API KEY。 |
| api_key_invalid | 401 | invalid_client |
API KEY 不正确,请核对 client_id 与 api_key 是否匹配。 |
| api_key_mismatch | 401 | invalid_client |
API KEY 与 client_id 不匹配,请确认二者属于同一应用。 |
| api_key_expired | 401 | invalid_client |
API KEY 已过期(超出有效期),请在控制台或 /v2/keys.php 中重新生成。 |
| api_key_revoked | 401 | invalid_client |
API KEY 已被轮换或手动作废,旧 KEY 不再生效。请使用新 KEY。 |
用户状态相关
| error_code | HTTP | 标准 error | 含义与处理建议 |
|---|---|---|---|
| user_banned | 403 | access_denied |
用户账号已被封禁,无法完成授权或访问受保护资源。 |
| user_not_approved | 403 | access_denied |
用户账号尚未通过审核,暂时无法完成授权。 |
| user_not_found | 404 | invalid_token |
用户不存在或已注销。 |
| user_not_logged_in | 401 | login_required |
用户未登录(prompt=none 场景下静默授权失败)。 |
授权与凭证相关
| error_code | HTTP | 标准 error | 含义与处理建议 |
|---|---|---|---|
| invalid_request | 400 | invalid_request |
缺少参数或参数不合法。 |
| missing_parameter | 400 | invalid_request |
缺少必要参数(如 code、client_id、refresh_token)。 |
| unsupported_method | 405 | invalid_request |
端点不支持当前请求方法,请使用文档标注的方法。 |
| unsupported_grant_type | 400 | unsupported_grant_type |
不支持的 grant_type。 |
| redirect_uri_mismatch | 400 | invalid_request |
redirect_uri 与授权时不一致。 |
| pkce_required | 400 | invalid_request |
公共客户端(App / SPA)必须使用 PKCE。 |
| pkce_failed | 400 | invalid_grant |
code_verifier 校验失败,检查生成与传输过程。 |
| invalid_grant | 400 | invalid_grant |
授权凭证无效(如授权码或刷新令牌与 client_id 不匹配)。 |
| code_invalid | 400 | invalid_grant |
授权码不存在,请检查是否复制完整。 |
| code_expired | 400 | invalid_grant |
授权码已过期(有效期 10 分钟),请重新发起授权。 |
| code_used | 400 | invalid_grant |
授权码已被使用,每个授权码只能兑换一次。 |
| refresh_token_invalid | 400 | invalid_grant |
refresh_token 不存在。 |
| refresh_token_expired | 400 | invalid_grant |
refresh_token 已过期,请重新授权。 |
| refresh_token_used | 400 | invalid_grant |
refresh_token 已被使用(一次性凭据),请重新授权。 |
| invalid_token | 401 | invalid_token |
访问令牌不存在或格式错误。 |
| token_expired | 401 | invalid_token |
访问令牌已过期,请使用 refresh_token 刷新。 |
| token_revoked | 401 | invalid_token |
访问令牌已被撤销,请重新授权获取。 |
| insufficient_scope | 403 | insufficient_scope |
权限范围不足。 |
| consent_required | 401 | consent_required |
需要用户授权(prompt=none 但用户尚未授权该应用)。 |
| access_denied | 403 | access_denied |
用户拒绝了授权。 |
安卓唤起验证相关
| error_code | HTTP | 标准 error | 含义与处理建议 |
|---|---|---|---|
| ticket_invalid | 400 | invalid_request |
验证票据不存在或已被消费。 |
| ticket_expired | 400 | invalid_request |
验证票据已过期(有效期 5 分钟),请重新申请。 |
| ticket_consumed | 400 | invalid_request |
验证票据已被使用,请重新申请。 |
| assertion_invalid | 400 | invalid_request |
身份断言签名不匹配、已过期或 audience 不符。 |
移动端登录相关
| error_code | HTTP | 标准 error | 含义与处理建议 |
|---|---|---|---|
| invalid_credentials | 401 | invalid-credentials |
账号或密码错误(不区分具体原因,避免账号枚举)。 |
| captcha_required | 400 | invalid-request |
平台开启了人机验证,但请求未提交验证码。 |
| captcha_invalid | 400 | invalid-request |
验证码错误、已被使用,或令牌签名不合法。请重新获取验证码。 |
| captcha_expired | 400 | invalid-request |
验证码已过期(有效期 5 分钟),请刷新后重试。 |
| account_disabled | 403 | access-denied |
账号已被停用,请联系平台管理员。 |
| refresh_token_invalid | 400 | invalid-grant |
刷新令牌无效或已被注销,请重新登录。 |
| refresh_token_expired | 400 | invalid-grant |
刷新令牌已过期,请重新登录。 |
| app_not_found | 404 | not-found |
应用不存在或不属于当前账号。 |
| not_found | 404 | not-found |
资源不存在或不属于当前账号。 |
限流 / 服务
| error_code | HTTP | 标准 error | 含义与处理建议 |
|---|---|---|---|
| rate_limited | 429 | slow_down |
请求过于频繁,请稍后重试(响应含 Retry-After 头)。 |
| server_error | 500 | server_error |
服务端异常,可稍后重试。 |
V1 端点
以下路径在过渡期内继续可用,但已不建议新接入。
Authorization Endpoint https://auth.401522.xyz/authorize.php Token Endpoint https://auth.401522.xyz/token.php UserInfo Endpoint https://auth.401522.xyz/api/userinfo.php User Endpoint https://auth.401522.xyz/api/user.php Refresh Endpoint https://auth.401522.xyz/api/refresh.php Revocation Endpoint https://auth.401522.xyz/api/revoke.php Introspection Endpoint https://auth.401522.xyz/api/introspect.php Discovery https://auth.401522.xyz/.well-known/openid-configuration
V1 的请求参数、调用方式与 V2 完全一致,示例:
POST https://auth.401522.xyz/token.php grant_type=authorization_code &code=RETURNED_CODE &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET GET https://auth.401522.xyz/api/userinfo.php Authorization: Bearer ACCESS_TOKEN
兼容别名:/v1/token.php、/v1/userinfo.php、/v1/refresh.php、/v1/revoke.php、/v1/introspect.php 均等价于对应的 V1 端点。
V1 错误码
V1 仅返回 error 与 error_description,无法区分「应用被封禁」与「应用未审核」等具体原因。这是迁移到 V2 的主要动因之一。
| error | 含义 |
|---|---|
invalid_request | 缺少参数或参数不合法(如公共客户端未使用 PKCE) |
invalid_client | client_id / client_secret 错误或应用被禁用 |
invalid_grant | 授权码或 refresh_token 无效、过期、已使用,PKCE 校验失败 |
unauthorized_client | 应用状态异常 |
access_denied | 用户拒绝授权 |
login_required | prompt=none 但用户未登录 |
consent_required | prompt=none 但用户尚未授权该应用 |
server_error | 服务端异常,可稍后重试 |
安全建议
- 移动端与 SPA 一律使用 PKCE,不要在客户端硬编码 client_secret。
- 校验
state,防止 CSRF;校验 ID Token 的iss、aud、exp。 - 回调地址使用 HTTPS;App Links 优先于自定义 Scheme。
- Access Token 只存于内存或加密存储,refresh_token 轮换后立即替换本地副本。
- API KEY 定期轮换(如每 30 天),并为轮换操作准备灰度切换方案。
- 网页唤起验证场景中,断言仅在服务端校验,切勿在前端直接信任。
- 发现泄漏时,在控制台「我的授权」立即撤销对应授权。