← [ BACK_TO_NOTES ]

Refresh Token

Refresh Token 是用于换取新 Access Token 的长期高价值凭证,通常低频使用,并需要服务端撤销、rotation 与 replay detection 等生命周期控制。

#concept #growing #security #backend #http

[!info] related notes

Refresh Token

一句话定义

Refresh Token 是客户端用来向 Authorization Server 换取新 Access Token 的长期凭证。它通常不直接用于访问业务 API,而是承担登录续期和会话生命周期控制。

它同样是“角色”,不是格式

Refresh Token
= 这个凭证拿来刷新 Access Token

JWT / opaque random string
= 它采用什么格式

Refresh Token 可以是 JWT,但很多系统更适合使用高熵随机 opaque token,并在服务端保存其 hash 与 Session / Grant 的映射。

典型刷新链

Access Token expired
        ↓
Client sends Refresh Token
        ↓
Authorization Server
        ↓
验证 refresh credential
检查 Session / Grant 生命周期
检查 user / revoke / expiry
        ↓
签发新的 Access Token

如果采用 rotation,还会同时返回新的 Refresh Token,并让旧 Refresh Token 失效。

为什么它比 Access Token 更敏感

Access Token 通常短期有效;Refresh Token 的作用是持续换取新的 Access Token,因此一旦泄露,攻击者可能长期维持访问能力。

所以 Refresh Token 通常需要更严格的:

  • 存储隔离;
  • 服务端撤销状态;
  • 过期时间;
  • rotation;
  • reuse / replay detection;
  • 设备或 Session 绑定。

Rotation 与重放检测

典型旋转:

RT1
 ↓ refresh
AT2 + RT2

RT1 立即失效

如果之后 RT1 再次出现,说明凭证可能被复制或请求被重放。服务端可以进一步撤销对应 refresh family、Session 或 Grant。

关键正确性要求是:

consume old refresh token
+
create replacement

应形成 single-winner 的原子状态转移,避免并发刷新让一个旧 Token 分叉出多个合法后代。

与 Server-side Session 的关系

Refresh Token 不是 Session 本身,但它经常指向或绑定一个长期 Session / Authorization Grant:

Refresh Token
      ↓ lookup / verify
Session / Grant
├─ user_id
├─ expires_at
├─ revoked_at
├─ device
└─ refresh family state

真正的长期登录生命周期可以由这份服务端状态掌握,而 Refresh Token 是客户端访问这份生命周期的高价值凭证。

服务端到底存什么 Token

不要把“客户端持有 Token”和“服务端保存 Token 状态”混成一件事。

Access Token

如果 Access Token 是自包含 JWT,通常不需要把原始 Access Token保存到 PostgreSQL 或 Redis:

Client
  ↓ Authorization: Bearer <JWT>
Server
  ↓ verify signature / claims

如果系统还要求立即登出、全局撤销等能力,可以额外在 Redis 保存 Session / revocation authority。此时 Redis 存的是服务端状态,而不是必须复制保存每个原始 Access Token。

Refresh Token

对于 opaque Refresh Token,更常见的安全模型是:

客户端:保存原始 Refresh Token

服务端:保存 digest/hash + session/family/expiry/status

类似密码存储,服务端不需要为了校验而长期保存可直接使用的明文 Refresh Token。收到客户端 Token 后计算 digest,再查询对应状态。

因此一个典型 Redis 模型可以是:

refresh:<digest>
→ session_id
→ family_id
→ active / consumed
→ TTL

Rotation 时旧 digest 转为 consumed / replay tombstone,新 Token 的 digest 成为 active。

Redis 还是 PostgreSQL

两者都可以承担 Refresh Session 状态,但职责不同:

  • Redis-only runtime state:适合把 Session、Refresh Token digest、rotation/replay state 作为带 TTL 的在线认证 authority;
  • PostgreSQL-backed session:适合还需要长期设备记录、登录历史、审计、复杂查询或 Redis 丢失后恢复 Session 的系统;
  • Hybrid:PostgreSQL 保存长期 Session / device / audit 事实,Redis 保存在线高频状态和撤销信息。

关键不是“Token 必须同时存两份”,而是先确定:哪些是长期业务事实,哪些只是在线认证状态。 即使需要 PostgreSQL,也通常优先保存 Session 元数据、digest 或审计记录,而不是原始 Refresh Token。

BodySense 当前心智模型

BodySense 当前把在线认证状态放在 Redis:Session authority、Refresh Token digest / rotation / replay detection 都属于 Redis 的高速状态层;用户、账户等长期事实仍由 PostgreSQL 承担。因此不需要为了 Refresh Token 本身再在 PostgreSQL 复制一份原始 Token。

浏览器中的存储

Browser 场景常把长期 Refresh Token 放在:

HttpOnly + Secure + 合适 SameSite 的 Cookie

这样前端 JavaScript 不需要读取它;刷新接口被调用时浏览器按 Cookie 规则自动携带。

这降低 JavaScript 直接窃取凭证的风险,但 Cookie 自动携带意味着仍要考虑 CSRF、SameSite、Origin/Referer 等安全边界。

Refresh Token 不一定每次都查关系数据库

服务端状态可以放在:

  • PostgreSQL / MySQL;
  • Redis;
  • 专门的 Auth Session Store。

关键不是存储介质,而是服务器拥有撤销、过期和 rotation 的权威状态。

边界与常见误解

  • Refresh Token 不等于 JWT。
  • Refresh Token 不应被当作普通 API Access Token 使用。
  • “长期”不意味着永久有效。
  • Refresh Token Rotation 不是简单生成一个新字符串;还要安全地使旧 Token 失效并处理并发和重放。
  • 如果系统完全采用 opaque server-side session,并通过滑动过期续期,则未必需要独立 Refresh Token。

学习检查

不看正文回答:

  1. Refresh Token 为什么是 credential role,而不是某一种固定格式?
  2. Access Token 与 Refresh Token 的寿命、暴露频率和撤销需求为什么不同?
  3. Rotation 为什么必须同时考虑旧 token 失效、并发刷新和 replay detection?
  4. 服务端保存 Refresh Session 时,为什么通常更适合保存 digest/metadata,而不是原始 token?
  5. Redis、PostgreSQL、Hybrid 分别适合承担哪些 session authority / audit 职责?
  6. HttpOnly Cookie 降低了哪类 XSS 风险,又为什么仍需考虑 CSRF / SameSite?
  7. 一个系统完全使用 server-side session 时,为什么可能不需要独立 Refresh Token?
  8. 画出一次 refresh request 从 credential → server authority → rotation → 新 access token 的完整链路。
创建于 2026/9/15 更新于 2026/9/30
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本