リフレッシュトークン
Refresh Token ・ りふれっしゅとーくん
アクセストークンを再発行するための長寿命トークン。安全と利便の折衷案。
概要
リフレッシュトークンは、OAuth などのトークンベース認証で、期限切れになったアクセストークンを再発行してもらうための長寿命トークンです。API を呼ぶために毎回提示するのがアクセストークン、それが切れたときに「新しいアクセストークンをください」と認可サーバに差し出すのがリフレッシュトークン、という分担になっています。
この二段構えのおかげで、アクセストークンの有効期限を数分〜1時間程度と大胆に短くしても、ユーザーは再ログインを求められません。スマホアプリを数週間ぶりに開いてもログインしたままなのは、裏でリフレッシュトークンが静かにアクセストークンを更新し続けているからです。「短命トークンの安全性」と「ログインし続けられる利便性」を両立させる折衷案 — それがリフレッシュトークンの本質です。
なぜ生まれたか
トークンベース認証には根本的なジレンマがあります。アクセストークンを長寿命にすれば、ユーザーは快適ですが、トークンが漏えいしたとき攻撃者も長期間使い放題になります。特にアクセストークンがJWTのような自己完結型(サーバに問い合わせず署名だけで検証できる形式)の場合、発行後に無効化するのが難しく、漏えいの被害は有効期限が尽きるまで続きます。かといって短寿命にすれば、ユーザーは数十分ごとにパスワードを入力し直すことになり、実用に耐えません。
この板挟みを解いたのが「役割の分離」です。頻繁にネットワークを飛び交い漏えいリスクの高いアクセストークンは短命にして被害を時間で限定し、代わりに長寿命のリフレッシュトークンを1枚だけ、厳重に保管して認可サーバとの間でのみ使う。リフレッシュトークンは認可サーバ側で管理されるため、怪しい動きがあれば即座に失効でき、「長寿命なのに取り消せる」性質を持ちます。サーバ側で状態を持つセッションの「いつでも無効化できる」利点を、トークン方式の世界に部分的に持ち込んだ設計とも言えます。
詳細
更新フローを順に追う
リフレッシュトークンの動きは、アクセストークンの期限切れをきっかけに始まります。典型的な流れを図で追ってみましょう。
クライアントが期限切れのアクセストークンで API を呼ぶと、リソースサーバは 401 を返します。クライアントはそこで再ログインを促すのではなく、認可サーバのトークンエンドポイントに grant_type=refresh_token のリクエストを送ります。認可サーバは、そのリフレッシュトークンが有効か、失効させられていないか、発行先クライアントと一致するかを検証し、問題なければ新しいアクセストークンを返します。ユーザーはこの往復に一切気づきません。実装上は「401 を受けてから更新する」方式のほか、有効期限を見て切れる少し前に先回りして更新する方式もよく使われます。
アクセストークンとの分担
両者の性格の違いを整理すると、この設計の意図がはっきりします。アクセストークンは「多数のリソースサーバに頻繁に提示される・短命・自己完結型なら失効が難しい」もの、リフレッシュトークンは「認可サーバ1箇所にだけ・たまに提示される・長命・サーバ管理なのでいつでも失効できる」ものです。露出の多い経路には失っても被害の小さいものを流し、価値の高いものは露出を最小にして取り消し可能にしておく — OAuth の認可コードフローが「経路の信頼度に応じて渡すものを変える」のと同じ思想が、時間軸方向にも適用されているわけです。
保管場所も重要です。リフレッシュトークンは「長期間有効なログイン権」そのものなので、モバイルアプリなら OS のセキュアストレージ(Keychain や Keystore)に保存します。SPA では JavaScript から読める場所(localStorage など)に置くと XSS 一発で盗まれるため、HttpOnly Cookie に載せる、あるいはリフレッシュトークンを持たず BFF(バックエンド側の仲介サーバ)にトークン管理を寄せる構成が推奨されています。
ローテーションと盗難検知
長寿命トークンである以上、盗まれたときの備えが設計の中心になります。現在のベストプラクティスが「リフレッシュトークンローテーション」です。更新のたびに新しいリフレッシュトークンを発行し、使用済みの古いトークンは即座に無効化します。リフレッシュトークンは毎回使い捨てになり、静かに漏えいしてもいつまでも使える、という状況がなくなります。
ローテーションの真価は盗難検知にあります。もし攻撃者がリフレッシュトークンを盗んで使うと、正規クライアントと攻撃者のどちらかが先に更新し、もう一方は「すでに使用済みのトークン」で更新を試みることになります。認可サーバはこの「使用済みトークンの再利用」を盗難のシグナルとみなし、そのユーザーのトークンファミリー(同じ系譜のトークン全部)を一括失効させて再ログインを強制できます。どちらが攻撃者か判別できなくても、全部止めれば安全側に倒せる、という割り切りです。
実務での設計論点
有効期限の設計では、リフレッシュトークン自体にも上限を設けるのが普通です。「最後の使用から30日」のようなスライディング方式(使い続ける限り延長)と、「初回ログインから90日で必ず再認証」という絶対期限を組み合わせ、利便性と「無限ログイン」の防止を両立させます。金融系など要件の厳しい領域では両方をぐっと短く設定します。
落とし穴としては、複数タブや複数リクエストが同時に更新を試みてローテーション済みトークンを再利用してしまい、正規ユーザーなのに盗難と誤判定される競合問題が知られています(更新処理の直列化や、ごく短い猶予期間の許容で対処します)。また、リフレッシュトークンで新しいトークンを取得できるのは発行時のスコープの範囲内だけであり、権限を広げたいときは再度ユーザーの同意を得るのが原則です。OIDC によるログインでも同じ仕組みで ID トークンやアクセストークンを更新でき、この設計は「ログインし続ける体験」を支える共通基盤になっています。
