アプリを使い続けているのに、毎回ログインし直さずに済むのはなぜでしょうか。

その仕組みの一つが、リフレッシュトークンを使ったアクセストークンの更新です。

リフレッシュトークンは、新しいアクセストークンを取得するために、認可サーバーへ提示する情報です。

ただし、持っていればいつまでも更新できるわけではありません。

この記事では、二つのトークンの使い分け、更新の流れ、失敗したときの確認、ローテーションによる保護を図で整理します。

解説者のアイコン
外資系エンジニア

この記事は以下のような人におすすめ!

  • アクセストークンとの違いを基礎から知りたい人
  • 更新に失敗して再ログインが必要になる理由を知りたい人
  • ローテーションや保存・同時更新の注意点を整理したい人

リフレッシュトークンの役割

1-1. APIを呼ぶものと、新しい利用権を受け取るものを分ける

アクセストークンは、保護されたAPIを利用するときに提示するものです。

リフレッシュトークンは、そのアクセストークンを新しく受け取るために使います。

送り先が違う点が大切です。

リフレッシュトークンは認可サーバーで使い、保護されたデータを返すリソースサーバーへは送りません。

また、リフレッシュトークンを発行するかどうかは、認可サーバーの判断によります。

(参考1)

アクセストークンを保護APIへ、リフレッシュトークンを認可サーバーへ送る用途の違いをラベルで示す図。
アクセストークンを保護APIへ、リフレッシュトークンを認可サーバーへ送る用途の違いをラベルで示す図。

図のA1とR1は、役割を区別するためのラベルです。

実際に使えるトークン文字列や、その中に入っている内容を表しているわけではありません。

「二つとも同じ鍵だから、同じ場所へ送ればよい」と覚えず、用途と送り先を一組にして理解しましょう。

1-2. 更新できることと、再ログインが不要なことは同じではない

更新が通れば、利用者に毎回操作してもらわず、新しいアクセストークンを受け取れる場合があります。

一方、リフレッシュトークン自体が使えなくなったり、サービスの方針で操作が必要になったりすることもあります。

そのため、アプリ側には、更新できないときに再認可などへ進める設計も必要です。

再認可は、アプリへ許可を与える手続きを改めて行うことです。

利用者が必ず毎回パスワードを入力するかどうかまで、この言葉だけで決まるわけではありません。

有効期限や失効後の案内はサービスによって異なり、Microsoftの公式資料でも、期限前に無効化される可能性と、その扱いが説明されています。

(参考3)

リフレッシュトークンは、無期限のログイン保証ではありません。

更新が成功する場合と、改めて利用者の操作が必要な場合を分けて考えます。

アクセストークンを更新する仕組み

2-1. 更新の要求は、認可サーバーへ送る

通常のAPI利用と、トークンを更新するやり取りを分けて見てみましょう。

アプリはアクセストークンA1を使ってAPIへアクセスします。

更新が必要になったら、認可サーバーのトークンエンドポイントへ、リフレッシュトークンR1を提示します。

エンドポイントは、要求を受け付ける窓口となるURLです。

認可サーバーは、トークンや必要なクライアント認証を確かめ、新しいアクセストークンを発行します。

(参考1)

アプリ・認可サーバー・APIの役割を分け、API利用とトークン更新の送り先を四つの矢印で示す図。
アプリ・認可サーバー・APIの役割を分け、API利用とトークン更新の送り先を四つの矢印で示す図。

図では、APIへ送る通信と、認可サーバーへ送る通信を分けています。

認可サーバーとAPIが同じ事業者のサービスでも、役割まで同じになるわけではありません。

更新要求に必要な認証方式は、アプリの種類や提供側の仕様に合わせて確認します。

実装時は対応する公式ライブラリを優先し、実トークンを確認画面やログへ貼り付けて試すことは避けましょう。

2-2. 新しい値が届くことと、権限が広がることは別

更新で新しいアクセストークンを受け取っても、勝手に許可範囲を広げられるわけではありません。

スコープは、アクセスを許された範囲を表す情報です。

RFC 6749では、更新で要求する範囲へ、もともと許可されていないスコープを含めてはならないとされています。

また、更新時に新しいリフレッシュトークンも発行される場合は、クライアント側で保存する値の入れ替えが必要です。

(参考1)

架空時刻と期限でアクセストークン更新を示し、新しい値の発行が権限拡大を意味しないことを添える図。
架空時刻と期限でアクセストークン更新を示し、新しい値の発行が権限拡大を意味しないことを添える図。

図の時刻や期限は、流れを説明するための架空例です。

すべてのサービスで同じ時間が使われるわけではありません。

さらに、新しいリフレッシュトークンが届いたことだけで、古い値がその場で使えなくなったとは判断できません。

この違いは、後のローテーションの章で分けて説明します。

期限切れや更新失敗をどう確認するか

3-1. 固定の日数より、提供側の条件を確かめる

「アクセストークンは一時間、リフレッシュトークンは何日」と覚えてしまうと、別のサービスで混乱します。

期限や失効の条件は、提供側やアプリの種類、組織の方針で変わります。

期限まで時間が残っていても、利用者がアプリへの許可を取り消せば、更新できなくなる場合があります。

Googleの公式資料でも、許可の取り消し、長期間の未使用、管理者の方針など、リフレッシュトークンが使えなくなる理由が複数示されています。

特定のスコープに関するパスワード変更の条件などもあるため、例をすべてのサービスへ当てはめないようにします。

(参考4)

invalid_grantとinvalid_clientの違い、診断に残す項目と秘密を残さない境界を示す確認票。
invalid_grantとinvalid_clientの違い、診断に残す項目と秘密を残さない境界を示す確認票。

先に確かめたいのは、どのサービスの、どのアプリで、どの段階が失敗したのかです。

APIへのアクセスが拒否されたことと、トークンの更新要求が拒否されたことを分けて記録します。

「ログインできない」という一つの言葉にまとめるより、次に読むべき資料や問い合わせ先を選びやすくなります。

3-2. invalid_grantを一つの原因と決め付けない

更新要求への応答にinvalid_grantとあっても、必ず期限切れという意味ではありません。

RFC 6749では、無効・期限切れ・失効・別のクライアントへ発行されたものなど、複数の原因を含むエラーとして定義されています。

一方、invalid_clientは、クライアントの認証に失敗したことを示す別の分類です。

(参考1)

応答のHTTPステータス、提供側のエラーコード、要求先、発生時刻、アプリの識別情報を、安全な範囲で残します。

実トークン、認証ヘッダー、クライアントシークレットの値をログや問い合わせ文へ貼り付ける必要はありません。

失効が確認されたときに、同じ値を何度も送っても元へ戻るわけではありません。

提供側の説明に従って、保存値や認証設定を確認し、必要な場合は利用者が再認可できる経路へ進めます。

通信切断や一時的なサービス障害まで同じ扱いにせず、再試行の条件も公式ライブラリや提供側の仕様で確認しましょう。

更新失敗のエラー名は、確認する方向を絞る材料です。

一つの名前から原因や対処を決め付けず、提供側の条件と照合します。

ローテーションと再利用への対策

4-1. 古い値の再利用を検出する方式

リフレッシュトークンが漏れると、新しいアクセストークンを取得される危険があります。

そのため、通信中だけでなく、保存時にも秘密を守る必要があります。

現在のOAuthのSecurity BCPであるRFC 9700は、パブリッククライアントに対する再利用への保護として、送信者に結び付ける方式、またはローテーションを求めています。

(参考2)

パブリッククライアントは、アプリ全体で共有する秘密を安全に保管できない種類のクライアントです。

送信者に結び付ける方式では、トークンを特定のクライアント実体へ暗号的に結び付けます。

ここでは、もう一方のローテーションを図で見てみましょう。

RFCの方式をR1とR2のラベルで示し、旧値の無効化・再利用検出・有効側の失効を分ける図。
RFCの方式をR1とR2のラベルで示し、旧値の無効化・再利用検出・有効側の失効を分ける図。

この方式では、更新時にR1からR2へ入れ替え、古いR1を無効にし、両者の関係を認可サーバー側へ残します。

古い値が再び使われれば、漏えいによる再利用の可能性を検出する材料になります。

ただし、再利用した側が正規アプリか攻撃者かまで、その事実だけで特定できるわけではありません。

図はRFCの方式を単純化した説明で、実サービスの実装や猶予時間を再現したものではありません。

4-2. 新しい値の発行と、旧値の無効化を混同しない

「更新で新しいリフレッシュトークンが届いた」ことだけでは、再利用検出の方式まで分かりません。

Microsoftの公式資料には、新しいアクセストークンを取得するために古いリフレッシュトークンを使っても、その古い値をその時点で失効させるわけではないという説明があります。

(参考3)

新しいRTの発行と旧値失効・再利用検出の方式を対比し、Microsoftの例を一般化しない図。
新しいRTの発行と旧値失効・再利用検出の方式を対比し、Microsoftの例を一般化しない図。

これを、先ほどの「古い値を無効化し、再利用を検出する方式」と同じ挙動だと考えないことが大切です。

また、RFCのローテーションで再利用が検出されると、有効なリフレッシュトークンも失効させるため、正規の利用者にも新しい許可の取得が必要になります。

(参考2)

トークンの値が変わること、古い値の有効性、再利用したときの処理は、別々の確認項目です。

製品の資料を読むときも、この三つを分けると説明を取り違えにくくなります。

ローテーションは、盗まれても安全という保証ではありません。

保存と通信の保護、再利用時の扱い、再認可へ戻る経路と合わせて考えます。

保存と複数処理の更新で注意すること

5-1. 通信中と保存時の秘密を守る

更新要求には、再びアクセスを得るための重要な情報が含まれます。

RFC 9700では、リフレッシュトークンの通信中・保存時の機密性や、TLSで保護された接続などが前提として説明されています。

(参考2)

実装するときは、利用する環境に合った保管方法と、公式ライブラリの管理方法を確認します。

サーバーで動くアプリ、モバイルアプリ、ブラウザーで動くアプリでは、使える保管先や守り方が同じとは限りません。

本稿では「どのアプリでも、この場所へ保存すれば安全」という一律の方法は示しません。

開発中のデバッグ表示、ログ、バックアップ、エラー送信にも値が混ざっていないかを確認してください。

運用担当者が原因を調べられる情報と、認証を再現できてしまう秘密の値は、分けて扱います。

通信路を守るTLSの基礎も、必要に応じて確認しておきましょう。

TLSとは?仕組みや重要性を初心者にもわかりやすく解説します!TLS(Transport Layer Security)についてわかりやすく解説します。オンラインセキュリティの重要性、具体的な動作プロセス、活用例、設定方法、問題点と解決策などをカバーしました。安心してオンラインで情報をやり取りするための知識を身につけましょう。...

5-2. 更新処理が重なる場合を設計に含める

一つのアプリでも、複数の画面や処理が同じ保存値を読むことがあります。

そこで同時に更新が走ると、古い値を使う要求や、新しい値の保存が重なる可能性があります。

ローテーションを使う設計では、とくにこの重なり方を考えておきたいところです。

処理AとBが同じR1を読み出した架空例を使い、同時更新と保存・不明応答の確認を提案する図。
処理AとBが同じR1を読み出した架空例を使い、同時更新と保存・不明応答の確認を提案する図。

図は、処理Aと処理Bが同じR1を読み出す架空の例です。

二つ目の要求が必ず同じエラーになることや、すべてのサービスで同じ猶予期間があることを示す図ではありません。

利用するSDKが更新をまとめているか、アプリ側で更新処理を一つにまとめる必要があるか、保存値をどう入れ替えるかを確認します。

保存に失敗した場合や応答を受け取れなかった場合も、無条件の再送を実装せず、提供側の仕様に合う回復方法を検討します。

ここでの排他や保存の確認は、本稿の設計上の提案です。

実サービスで動作を確認した結果や、共通の再試行手順ではありません。

よくある疑問と更新の確認点

6-1. リフレッシュトークンについてよくある五つの質問

Q1:リフレッシュトークンをAPIへ送れば使えますか?

アクセストークンと用途が違います。

更新に使う情報は認可サーバーへ提示し、保護されたデータを返すAPIへは送りません。

Q2:必ず発行されますか?

発行は認可サーバーの判断によります。

使うサービスやフローの条件を確認してください。

Q3:有効期限は何日ですか?

一律の日数ではありません。

サービス、アプリの種類、組織の方針、失効条件を確かめる必要があります。

Q4:新しい値が届いたら、古い値はもう使えませんか?

届いたことだけでは判断できません。

古い値の無効化や再利用時の処理は、提供側の説明で確認します。

Q5:invalid_grantなら、期限切れですか?

期限切れだけでなく、失効やクライアントの不一致なども含む分類です。

応答とサービス固有の条件を合わせて調べましょう。

送り先、任意発行と期限、失敗の分類、public-clientの再利用保護、保存、回復経路を整理する図。
送り先、任意発行と期限、失敗の分類、public-clientの再利用保護、保存、回復経路を整理する図。

6-2. 用途・失敗・保存を分けて整理する

最初に覚えたいのは、「APIに使うもの」と「新しく受け取るためのもの」の違いです。

次に、更新は必ず成功するわけではなく、期限や許可の取り消しなどの条件があることを押さえます。

ローテーションの設計では、新しい値の発行だけでなく、古い値の無効化と再利用の検出まで確認します。

最後に、値を安全に保存し、複数の処理や通信障害があっても扱えるように考えます。

こうして順番に分けると、「ログインし直せばよい」「同じ要求を繰り返せばよい」といった一律の対処から離れられます。

具体的な実装では、利用する認可サーバーと公式ライブラリの資料を、対象のアプリ種類に合わせて確認してください。

参考資料