Refresh Token 輪替
最後更新
本頁說明 Access Token 過期後 VerifyJWT() 如何在同一個請求內續期,以及 Refresh ID 何時換發。
觸發條件
續期只在下列兩種情況發生,Access Token 仍有效時不碰 Redis 的 Refresh 資料:
| 情境 | 取得 Refresh ID 的方式 |
|---|---|
Access Token 已過期(jwt expired) |
解碼過期 Token 內的 refresh_id |
| 沒有 Access Token,但有 Refresh ID | X-Refresh-ID header 或 Refresh cookie |
續期流程
sequenceDiagram
participant C as 客戶端
participant A as VerifyJWT
participant R as Redis
participant U as checkUserExists
C->>A: 過期 Access Token 或僅 Refresh ID
A->>R: GET refresh:id,比對指紋
A->>R: TTL refresh:id,version + 1
opt version > 5 或剩餘 TTL < refreshTokenExpires / 2
A->>R: 舊鍵 SETEX 5 秒
A->>A: 產生新 Refresh ID,version 歸零
end
A->>R: SETEX refresh:id(refreshTokenExpires)
A->>U: 使用者是否存在
A-->>C: 新 Access Token + Refresh ID(Set-Cookie 與 X-New-*)
換發規則
| 條件 | 行為 |
|---|---|
| 每次續期 | version + 1、expires_at 延長,Redis TTL 重設為完整 refreshTokenExpires |
version > 5 |
換發新 Refresh ID |
剩餘 TTL 小於 refreshTokenExpires / 2 |
換發新 Refresh ID |
| 換發時 | 舊鍵保留 5 秒,讓同時送出的請求仍能用舊 ID 續期 |
CreateJWT() 建立的 Refresh 資料 version 為 1:前 4 次續期沿用同一個 ID,第 5 次續期時 version 變成 6 而換發。換發後 version 歸零,之後第 6 次續期再換發一次。
每次續期都會把 TTL 重設為完整壽命,所以 Refresh ID 的有效期是滑動的:持續使用的工作階段不會過期;超過 refreshTokenExpires 未使用才會失效。
續期時寫回的內容
| 位置 | 內容 |
|---|---|
X-New-Access-Token header |
新的 Access Token |
X-New-Refresh-ID header |
目前的 Refresh ID(換發時為新值) |
| Access cookie | 新 Access Token,壽命 accessTokenExpires |
| Refresh cookie | Refresh ID,壽命 refreshTokenExpires |
新 Access Token 的 payload 為登入時存入 Refresh 資料的使用者快照,加上 fp、version、refresh_id。