管理会话
登录是会话的起点,不是集成的终点。Connect 提供四个端点处理登录之后的会话生命周期:/refresh、/introspect、/logout、/revoke-all。本页是它们的唯一参考。
走 OIDC 流程的用户另请参考 OIDC 指南中的 /end-session —— 它有相关但更窄的用途。
| 端点 | 鉴权凭据 | 幂等? | 影响范围 |
|---|---|---|---|
POST /refresh | refresh token 本身 | 否(轮换 refresh token —— 每个令牌只能用一次) | 单个会话 |
POST /introspect | access token 本身 | 只读 | 单个会话 |
POST /logout | refresh token 本身 | 是(两次调用都返回 revoked: true) | 单个会话 |
POST /revoke-all | Client-auth JWT(RS256) | 是 | 某账户在调用应用下的所有会话 |
这四个端点都不需要额外的基础设施 —— 复用你最初集成时就已经有的密钥。
/refresh —— 延续会话
Section titled “/refresh —— 延续会话”用 refresh token 换取一个新的 access token 和一个新的 refresh token。刷新采用严格轮换(OAuth 2.1 BCP §4.14.2):你提交的 refresh token 在同一次调用中被消费并作废,响应里会把它的替代者交给你。请存下新的 refreshToken,并在下一次刷新时使用它。重复提交一个已经用过的 refresh token 会被视为令牌族被攻陷 —— 整个 refresh token 族都会被吊销,用户必须重新认证。例外是对同一个令牌近乎同时的并发刷新(例如两个浏览器标签页同时刷新):它们会收敛到同一个新会话,而不会把用户登出。但在替代令牌已签发之后再复用旧令牌仍会触发失陷,所以无论如何都请始终存储并使用最新轮换出来的令牌。
curl -X POST https://connect-api.sudomimus.com/refresh \ -H "Content-Type: application/json" \ -d '{ "refreshToken": "..." }'响应:
{ "accessToken": "<JWT>", "refreshToken": "<轮换后的 JWT>", "claims": { "email": { "requirement": "REQUIRED", "state": "GRANTED" }, "firstName": { "requirement": "OPTIONAL", "state": "GRANTED" }, "lastName": { "requirement": "OFF", "state": "UNKNOWN" } }}请持久化轮换后的 refreshToken,替换掉你刚用过的那个 —— 旧的现在已经失效。claims 块与 /redeem 返回的逐条声明视图相同 —— 如何解读见 claims 块。
鉴权:无需 —— 持有 refresh token 即是凭据。
新的 access token 的 TTL 是最初 /redeem(或 /direct-issue/*、OIDC /token)时算出的那一份;refresh 不会重新决议 TTL。
Refresh 可能因声明而失败
Section titled “Refresh 可能因声明而失败”/refresh 的结果不只有成功或令牌被吊销。如果自上次签发令牌后,某条 required 声明不再满足,例如开发者将策略从 optional 改为 required,或用户撤销授权,本次刷新会返回 ClaimConsentRequired,而不会签发缺少该声明的令牌。
补救方式取决于客户端类型,因为 /refresh 自己无法收集同意:
- 原生客户端(Steam / AccessKey)靠重新跑一次原本的 direct-issue 来补救,它会返回一个 Errand 交接,让用户授予同意。
- 浏览器应用靠再次引导用户走一次常规交互式登录来补救。
这在实践中很少见 —— 只在策略或授权于会话中途变化时才会发生 —— 但请把你的刷新路径设计成弹出重新认证提示,而不是把每一次刷新失败都当成强制登出。
/introspect —— 这个令牌还有效吗
Section titled “/introspect —— 这个令牌还有效吗”向 Sudomimus 查询某个 access token 的当前状态。用它实现「跨服务及时撤销会话」—— 例如用户点击「在所有设备退出」后,希望其他标签页或服务能在有限时间内察觉。
curl -X POST https://connect-api.sudomimus.com/introspect \ -H "Content-Type: application/json" \ -d '{ "accessToken": "..." }'响应:
{ "status": "active", "recommendedRecheckSeconds": 600}status 可取:
"active"—— 关联的 refresh token 存在、未被挂起、未过期。"revoked"—— 关联的 refresh token 已被显式挂起(通过/logout或/revoke-all)。"expired"—— 关联的 refresh token 已过期。"not_found"—— 在调用应用下找不到该令牌,或令牌无法解析。
recommendedRecheckSeconds 是 Sudomimus 建议的缓存时长,超过之后再次 introspect。目前总是 600 秒。把 access token 自己的 exp 当作有效期上限;introspect 是用来及时发现撤销的,不是用来替代签名验证。
鉴权:无需 —— access token 本身就是凭据。任何持有该令牌的一方都能问它是否还有效。
什么时候调 introspect
Section titled “什么时候调 introspect”本地签名验证负责正确性;introspect 负责新鲜度。一个合理的搭配:
- 每次请求都本地验证 access token 的签名和
exp(开销很小)。 - 机会主义地调
/introspect—— 每 N 分钟一次、放进后台任务,或者在用户可见的状态变化后调用。
不要每次请求都 introspect,否则就失去了使用签名令牌的初衷。
/logout —— 单会话失效
Section titled “/logout —— 单会话失效”挂起一个 refresh token。其对应的 access token 在 /introspect 上不再被报告为 active,对它的 /refresh 也会失败。
curl -X POST https://connect-api.sudomimus.com/logout \ -H "Content-Type: application/json" \ -d '{ "refreshToken": "..." }'响应:
{ "revoked": true }revoked: true—— 令牌被挂起(或者本来已经被挂起/过期;重复调用没问题)。revoked: false—— 令牌无效或未找到。
鉴权:无需 —— 持有 refresh token 即可对这个会话登出(RFC 7009 风格)。
/revoke-all —— 吊销账户所有会话
Section titled “/revoke-all —— 吊销账户所有会话”挂起某账户在调用应用下签发的所有 refresh token。用于账户接管事件响应、「在所有设备登出」,或支持团队发起的会话终止。
账户通过其 扇区主体(sector subject) 标识 —— 即你的应用在令牌上看到的 subject 值(你用来标识用户的那个 sub),而非原始账户 UUID。Sudomimus 会在内部把它反向映射回底层账户。
curl -X POST https://connect-api.sudomimus.com/revoke-all \ -H "Content-Type: application/json" \ -H "Authorization: SudomimusClientJWT $SUDOMIMUS_CLIENT_AUTH_JWT" \ -d '{ "subject": "sub_9SQ5535CRWNDDM2T" }'响应:
{ "revokedCount": 3 }revokedCount 是本次调用挂起的 refresh token 数量。已经挂起或已过期的不会被重复计数。
鉴权:和 /establish 一样需要 client-auth JWT。操作范围是隐式的 —— 只触及调用应用下签发给该账户的会话。无法用某应用的 client-auth 密钥撤销另一个应用的会话。
串起来 —— 典型会话生命周期
Section titled “串起来 —— 典型会话生命周期” /redeem ──► access (3h) refresh (30d) │ │ │ │ ▼ │ 每次请求都用 │ │ │ ▼ 过期 │ /refresh ◄──────────────┤ 新 access + 轮换 refresh │ │ ▼ │ │ │ 用户点击「登出」 ──► /logout │ ▼ 吊销 │ /introspect ──► "revoked"OIDC 风格的 refresh 见 OIDC 接入方 —— Refresh。