为什么要有 refresh token?轮换是什么?令牌被偷了怎么发现?登出之后访问令牌还能用吗?这篇用真实的令牌流程把每种情况的状态码打印出来。
登录得到 access + refresh;/me → 200
2 秒后 /me → 401 {'error': 'ExpiredSignatureError'}
/refresh → 200 拿到新的 access 与新的 refresh(两者都变了): True True
新 access 访问 /me → 200 再用已经用过的旧 refresh → 401 {'error': 'refresh token reuse detected; family revoked'}
此后连合法的新 refresh 也失效 → 401 {'error': 'family revoked'}
(整个「家族」被撤销:攻击者和真用户都得重新登录) 第一次 /refresh → 200 (但假设响应在路上丢了,客户端没收到新令牌)
客户端用旧令牌重试 → 401 {'error': 'refresh token reuse detected; family revoked'}
服务端发出的那个新令牌也作废了 → 401
(严格的轮换会把这种合法重试当成重用;常见的缓解是给旧令牌一个几秒的宽限期——本篇没有实现) 登出后用刷新令牌 → 401 {'error': 'family revoked'}
但登出前签发的访问令牌还能用(过期前):/me → 200
刷新令牌放了 5 秒之后 → 401 {'error': 'refresh token expired'}
乱写的刷新令牌 → 401 {'error': 'unknown refresh token'}Set-Cookie: refresh=<令牌>; Expires=Fri, 02 Oct 2026 05:07:52 GMT; Max-Age=5; Secure; HttpOnly; Path=/refresh; SameSite=Strict 响应正文里只有 access,没有 refresh: ['access']