refresh token ローテーションには猶予窓を設け、並行 refresh の敗者をログアウトさせない
セキュリティ
認証・認可
知識
判断
refresh トークンをローテーションし、使用済みトークンの再提示を盗難兆候としてトークンファミリー一括失効させる設計は、マルチタブ・多デバイスの並行 refresh と衝突する。複数タブが同時に復元を試みると、遅れて到着した側は「使用済みトークンの再提示」に見えるため、正当な利用者が全ログアウトさせられる。
対処: 後継トークンの存在による猶予判定
失効済みトークンの提示を受けたとき、**そのトークンを親とする後継(rotated_from 関係)が猶予窓(例: 30秒)以内に発行されていれば「並行 refresh の敗者」**として扱う。
- 敗者の場合: ファミリー失効も cookie 削除も行わず、401 のみを返す。呼び出し側はリトライか、勝者が書いた cookie でそのまま復元される。
- 後継が存在しない/後継が猶予窓より古い場合: 従来どおり盗難兆候として一括失効する。
猶予窓は「同時刻の並行リクエスト」を吸収する長さに留める。長すぎると盗まれたトークンの再利用窓になる。
検証すべきケース
- 猶予窓の内側/外側での再提示
- 並行 refresh の敗者(後継が存在する失効トークン)
- 単純な使い回し(後継なし)で従来どおり一括失効すること
一般化
この構造は「一度しか使えない資格情報」を並行アクセス下で扱うとき共通に必要になる。再利用検知は正当な並行アクセスと区別できて初めて安全側になる。区別しないまま厳しくすると、攻撃を防ぐ代わりに正当な利用者を落とす。