跳转到内容

令牌生命周期实践

每份 OAuth 流程指南都会提到 refresh_token,但一个长时间运行的集成(需要持续跨越大量请求、多个 worker 或多天运行)需要的不只是”过期就换一个令牌”。本页介绍真实的令牌有效期、如何在多个 worker 之间缓存令牌、何时刷新,以及有哪些因素会在令牌本应到期之前就使其失效。


访问令牌的有效期是一个固定时长,所有流程都相同。刷新令牌则不同:它取决于是哪种 OAuth 流程签发的。

流程访问令牌 TTL刷新令牌 TTL
Client Credentials 流程约 1 小时约 30 天
Native Application 流程(PKCE,回环重定向)约 1 小时无固定到期时间:在被轮换替换或被撤销之前始终有效
Authorization Code + 自定义重定向流程约 1 小时无固定到期时间:在被轮换替换或被撤销之前始终有效

缓存令牌,不要每次请求都重新签发

Section titled “缓存令牌,不要每次请求都重新签发”

在每次 API 调用时,或在每个 worker 进程中各自独立地请求新的访问令牌,虽然可行,但会为一个本已能用约 1 小时的令牌,在每一次请求上都白白浪费一次往返。只请求一次令牌,以签发它所用的凭据为键将其缓存(单进程可放在内存中,多个 worker 组成的集群可放在 Redis 等共享存储中),并在令牌接近到期前,持续把缓存的令牌交给每一次请求使用。

这一点对刷新令牌同样重要:独立交换它的进程越少,遇到下文所述竞态问题的可能性就越小。

按到期时间刷新,而不仅是在收到 401 时

Section titled “按到期时间刷新,而不仅是在收到 401 时”

由于访问令牌的 TTL 是固定且预先可知的,应主动刷新:记录获取令牌的时间(或解码其 exp 声明),在到期前不久就请求新令牌,而不是等到请求先失败。

不过仍应把请求失败当作后备处理,但要根据收到的错误加以区分:

  • 带 not_authenticated 的 401:请求根本没有携带可用的 bearer 令牌。这是客户端问题(Authorization 头缺失或格式错误),而不是需要刷新的信号。
  • 带 invalid_token 的 401:令牌的签名或到期检查未通过。刷新后重试一次。
  • 403:从来都不是令牌问题。令牌本身有效,只是调用方缺少该操作所需的 scope、内容访问权限或角色。刷新解决不了这个问题。每个代码的完整说明见错误代码:速率限制、身份验证与访问控制。

刷新令牌是一次性的:用 grant_type=refresh_token 交换它会使该刷新令牌失效,并同时签发一个新的访问令牌和一个新的刷新令牌。如果多个 worker 共享同一个缓存的刷新令牌,其中两个几乎同时尝试刷新,只有一次交换会成功;另一个会收到一个通用的 401,而不是一个可区分的”已被使用”错误。

以下事件都不会直接吊销一个仍然有效的访问令牌。每一项只会阻止新的操作(新的令牌请求,或下一次刷新)而你手上已有的访问令牌会一直有效,直到它自身的 TTL 用尽。

触发条件影响
OAuth 应用的客户端密钥被轮换使用旧密钥发起的新令牌或刷新请求会被立即拒绝。已签发的访问令牌不受影响,会照常运行到自然到期。
OAuth 应用或其服务用户被移除阻止为该应用签发新令牌。已签发的令牌不会被主动吊销。
OAuth 应用的 scope 发生变更已签发的访问令牌在其剩余有效期内仍保留原有 scope。只有在下一次刷新或重新签发时,令牌才会采用新的 scope。
授权被显式撤销立即阻止下一次刷新尝试。仍然有效的访问令牌不会被强制失效,会照常运行到自然到期。