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。

相關:驗證結果、Redis 鍵

EN