令牌生命周期管理

访问令牌短期有效、刷新令牌长期持有并一次性轮换;过期与刷新失败要区分处理(重新登录与静默刷新),客户端与服务端时钟偏差要留出容忍窗口。

令牌生命周期怎么设计

OAuth 类体系通常采用两种令牌搭配:访问令牌有效期短(分钟级),用于携带权限调用接口,泄露窗口小;刷新令牌有效期长,用于在访问令牌过期后换新。关键设计点是刷新令牌一次性使用并在使用后轮换——旧刷新令牌立即失效,如果它再次出现,说明已经泄露,应该吊销整个会话并告警。客户端要能区分“过期需要刷新”和“凭证失效需要重新登录”两种情况。

基本信息

访问令牌分钟级有效期,减少泄露窗口
刷新令牌长期有效,使用后轮换并检测重放
处理过期返回 401 并提示刷新;刷新失败引导重新认证
时钟容忍校验时留出少量时间偏差容忍窗口,避免边界请求被误判过期

典型使用场景

  • 移动端与单页应用:用短期访问令牌加刷新令牌,避免频繁登录
  • 第三方接入:为每个授权关系维护独立的刷新令牌与吊销状态
  • 多端登录管理:按设备维护会话,支持单设备登出与全端登出
  • 权限变更:调整用户权限后按会话吊销,避免旧令牌继续持有高权限
  • 风控场景:检测到异常登录后立即吊销相关刷新令牌

刷新流程(伪代码)

刷新流程(伪代码)
on401(response):
  if (refreshToken 有效):
    新令牌对 = refresh(refreshToken)   // 旧刷新令牌立即失效
    重放原请求一次
  else:
    清除会话 → 引导重新登录

状态与处理

状态判定客户端动作
访问令牌过期401 且错误码表示令牌过期静默刷新后重放一次原请求
刷新令牌过期刷新接口返回无效授权清除会话并引导重新登录
刷新令牌被重放服务端检测到已轮换的旧令牌吊销该会话全部令牌并告警
权限不足403 而非 401不做刷新,提示权限问题
并发刷新冲突多个请求同时触发刷新客户端单飞:只发起一次刷新,其余请求等待结果

使用要点

  • 刷新令牌轮换配合重放检测:旧令牌再次出现时按泄露处置,吊销会话并告警
  • 客户端区分 401 与 403:前者可能通过刷新恢复,后者刷新无效只会浪费请求
  • 并发请求要单飞刷新:多个请求同时刷新会互相作废令牌,形成刷新风暴
  • 过期时间留容忍窗口:客户端与服务端时钟偏差会导致边界请求被误判,判断提前量通常取数十秒
  • 会话与设备绑定要可审计:能列出并单独吊销某一设备的会话
刷新令牌轮换配合重放检测:旧令牌再次出现时按泄露处置,吊销会话并告警,而不是简单返回错误,否则泄露无法被发现。
把刷新令牌存进浏览器可被脚本读取的位置(如普通 localStorage)会放大 XSS 影响:存储位置与传输方式要与整体前端安全方案一起决定。

易错点

  • 刷新令牌长期不轮换,泄露后长期可用,且无法判断是否已被他人使用
  • 客户端把 401 一律当网络错误重试,陷入死循环或反复刷新失败
  • 并发请求各自发起刷新,多个刷新请求互相作废令牌,用户被动登出
  • 服务端不校验刷新令牌与设备的绑定关系,被盗令牌可在异地长期使用
  • 权限变更后不吊销存量会话,降权用户在令牌过期前仍持有旧权限

数据来源与参考

  • RFC 9700:OAuth 2.0 Security Best Current Practice
  • RFC 6749:OAuth 2.0
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌