LASSIC Media らしくメディア
アクセストークンとリフレッシュトークンの違い、期限と保存場所
監修・編集責任者:牛尾 昭昌(株式会社LASSIC 執行役員)
この記事の結論
- アクセストークンはAPIに見せる短命の許可証、リフレッシュトークンはそれを取り直すために認可サーバーだけに見せる資格情報です。
- 期限はアクセストークンを短く、リフレッシュトークンは使われない期間と最初の発行からの上限の2つで切ります。
- 保存場所はクライアントの種類で決め、ブラウザのlocalStorageには置かず、ローテーションと失効の動きまで試験します。
※ 本記事は2026年10月時点の公式情報(省庁・公的機関、および製品やサービスを提供する事業者が公開している資料)に基づきます。
アクセストークンとリフレッシュトークンを発行する設計になったものの、それぞれの期限を何分、何日にすればよいのか決めきれない。ブラウザやスマートフォンアプリのどこにトークンを置けばよいのかも分からない——。Web APIやアプリに認可の仕組みを組み込む開発の現場では、こうした迷いが起こりがちです。アクセストークンはAPIを呼び出すときに提示する短命の許可証、リフレッシュトークンはその許可証を取り直すために認可サーバーだけに提示する、寿命の長い資格情報を指します。
2つを組み合わせると、漏れたときの被害を小さく保ちながら、利用者に何度もログインを求めずに済みます。ただし万能ではなく、リフレッシュトークンの扱いを誤ると、長い期間にわたって不正なアクセスを許す入口になります。本記事では、Webシステムやアプリの開発・運用に携わる方に向けて、2つのトークンの仕組みと違い、期限の決め方、保存場所、つまずきやすい点、そして外部に頼むときに確認したい点を整理します。
目次
2つのトークンの役割
OAuth 2.0の仕様であるRFC 6749は、アクセストークンを「保護されたリソースにアクセスするための資格情報」、リフレッシュトークンを「アクセストークンを取得するための資格情報」と定めています。*1 どちらもクライアント(APIを呼び出すアプリ)から見ると中身を読み取れない文字列であることが多く、トークンの形式そのものは仕様で決められていません。OAuthの全体像は「OAuth入門」で扱っています。
いちばん大きな違いは、提示する相手です。アクセストークンは、APIを提供するリソースサーバーへ送ります。リフレッシュトークンは、トークンを発行する認可サーバーだけに送り、リソースサーバーには送りません。また、リフレッシュトークンを発行するかどうかは認可サーバーの判断に任されていて、発行されない構成もあります。
2つのトークンはどちらも認可(何をしてよいかの許可)の仕組みで、ログインした本人の情報を受け渡すOpenID ConnectのIDトークンとは別物です。この区別は「認証と認可の違い」で整理しています。
トークンを取り直す仕組み
流れはRFC 6749の図2のとおりです。クライアントは認可グラント(利用者の同意を示す認可コードなど)と引き換えに2つのトークンを受け取り、アクセストークンを付けてAPIを呼び出します。期限が切れてエラーが返ったら、リフレッシュトークンで新しいアクセストークンを取り直します。
発行時の応答は次のようなJSONです(RFC 6749の例をもとにしたもの)。expires_inは有効期間を秒で表し、3600なら応答の時点から1時間で切れます。*1 応答にはCache-Control: no-storeを付け、キャッシュに残さないようにします。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
}
アクセストークンが切れたら、クライアントはトークンを発行する窓口(トークンエンドポイント)に次のリクエストを送ります。grant_typeにrefresh_tokenを指定し、手元のリフレッシュトークンを渡します。秘密の資格情報を持てるクライアントは、ここでクライアント自身の認証も行います。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
応答で新しいリフレッシュトークンが返ってきたら、クライアントは古いものを捨てて新しいものに置き換えます。RFC 6749はこれを必須としています。更新で求める範囲(scope)は、最初に利用者が許可した範囲を超えて広げられません。
2つのトークンの違い
| 観点 | アクセストークン | リフレッシュトークン |
|---|---|---|
| 提示する相手 | リソースサーバー(API) | 認可サーバーだけ |
| 期限の長さ | 短い | 長い |
| 使われ方 | API呼び出しのたびに送る | アクセストークンが切れたときだけ送る |
| 漏れたときの影響 | 期限が切れるまで、許された範囲で使われる | 新しいアクセストークンを作られ続けるおそれがある |
| 主な守り方 | 短い期限、範囲と宛先の限定 | クライアントとの結び付け、ローテーション、失効 |
表のうち、期限の長さと漏れたときの影響は表裏の関係にあります。アクセストークンは多くの場合、ベアラートークン(持っている人なら誰でも使えるトークン)として扱われます。RFC 6750は、ベアラートークンを1時間以内の短い期限で発行するよう勧めています。*2 漏れても悪用できる時間を限れるからです。
一方、OAuth 2.0のセキュリティのベストプラクティスをまとめたRFC 9700は、リフレッシュトークンを攻撃者にとって魅力的な標的としています。*3 特定のリソースサーバーに縛られず、許された範囲全体のアクセストークンを作れてしまうからです。アクセストークンを短くできる分、リフレッシュトークンは厳重に守ります。
アクセストークンをJWT(署名付きのJSON形式のトークン)で発行すると、リソースサーバーは署名だけで検証できる代わりに、発行済みのトークンを期限の途中で止めにくくなります。JWTの構造と検証は「JWTとは」で解説しています。
期限の決め方
期限の値はRFCでは決まっていないため、大手の認可サーバーが公開している既定値が手がかりになります。
| 資料 | アクセストークン | リフレッシュトークン |
|---|---|---|
| Microsoft ID プラットフォーム | 60〜90分の間で発行ごとにばらつく(平均75分)*4 | SPA(ブラウザだけで動くアプリ)は24時間、それ以外は90日*5 |
| Google の OAuth 2.0 | 有効期間は限られている | 6か月使われないと働かなくなる。テスト中の外部向けアプリは期限7日*6 |
| IETF のブラウザ向けアプリの草案(例示) | 10分 | 最初の発行から8時間が上限*7 |
Microsoftが期限をばらつかせているのは、更新の要求が毎時の同じ時刻に集中しないようにするためだと説明されています。
ただし、期限は短いほどよいわけではありません。RFC 6819は、短い期限は漏えいや推測による攻撃への備えになる一方、サーバー間の時刻をより正確にそろえる必要があり、更新も増えると注意しています。*8 業務システムなら、アクセストークンはRFC 6750の勧める1時間以内で、APIの重要度に応じて短めに決めます。
リフレッシュトークンには、性質の違う2つの期限を組み合わせます。1つは、一定期間使われなければ切れる期限です。RFC 9700は、しばらく使われていないリフレッシュトークンは失効させるべきだとしています。もう1つは、最初の発行から数えた上限です。上の草案は、トークンを入れ替えても最初の期限より先へ延ばしてはならないとしており、表の例では8時間たてば改めてログインします。
保存場所の選び方
RFC 6749は、どちらのトークンも通信中と保存中の両方で秘密に保つよう求めています。そのうえで、どこに置くかはクライアントの種類で変わります。
| クライアントの種類 | アクセストークン | リフレッシュトークン |
|---|---|---|
| サーバー側で動くWebアプリ | サーバーのメモリやキャッシュ | サーバー側のデータベースに暗号化して保存し、ブラウザには渡さない |
| ブラウザだけで動くアプリ | BFFを置いてブラウザに渡さないのが第一候補。直接持つならメモリ上に置く | BFFに持たせる。ブラウザのlocalStorageには置かない |
| スマートフォンアプリ | アプリのメモリ上 | iOSのKeychainやAndroid Keystoreで保護した領域 |
RFC 6819は、アクセストークンを、そのクライアントアプリだけが読める一時的なメモリに置くよう勧めています。*8 消えてもリフレッシュトークンで取り直せます。
ブラウザで動くアプリは、悪意のあるスクリプトを埋め込まれると、同じオリジン(URLのスキーム・ホスト・ポートの組)で動くコードからトークンを読まれます。IETFの草案は、localStorageはこの読み取りを防げないと指摘しています。*7 そこで同じ草案は、BFF(Backend For Frontend:画面専用のサーバー側の部品)がトークンを保管し、ブラウザとはHttpOnlyとSecureの属性を付けたCookieでつなぐ構成を示しています。手口は「XSS(クロスサイトスクリプティング)の仕組みと対策」、Cookieは「Cookieとセッションの違いと仕組み」を参照してください。
スマートフォンアプリでは、OSが用意する保護された保存領域を使います。端末内の暗号化と鍵の扱いは「アプリの端末内データ暗号化の実装」で扱っています。どのクライアントでも、トークンはURLに載せず、ログにも書き出しません。RFC 6750も、ページのURLでベアラートークンを渡すべきではないとしています。
つまずきやすい点
1つ目は、ローテーション(使うたびにリフレッシュトークンを入れ替える方式)の扱いです。RFC 9700は、秘密の資格情報を持てないパブリッククライアント(ブラウザやスマートフォンのアプリ)に、リフレッシュトークンを送り手に暗号的に結び付けるか、ローテーションを使うことを必須としています。*3 ローテーションでは、入れ替え済みの古いトークンが再び使われると漏えいを疑い、有効なトークンまで失効させます。そのため、複数のタブやサーバーが同時に更新すると、正規の利用者がログアウトさせられます。RFC 6819も、クラスター構成では問題が起きうると注記しています。
対策は、更新の処理を1か所にまとめることです。次の例は、アクセストークンをメモリに置き、更新はサーバー側の窓口に任せる画面側のコードで、401が同時に返っても更新は1回だけ送ります。タブをまたぐ重なりは、サーバー側で同じ利用者の更新を順番に処理して防ぎます。
let accessToken = null; // メモリにだけ置く
let refreshing = null;
async function callApi(url) {
const res = await fetch(url, { headers: { Authorization: `Bearer ${accessToken}` } });
if (res.status !== 401) return res;
// 同時に401を受けても、更新の要求は1回だけ送る
refreshing ??= refresh().finally(() => { refreshing = null; });
await refreshing;
return fetch(url, { headers: { Authorization: `Bearer ${accessToken}` } });
}
async function refresh() {
const r = await fetch('/auth/refresh', { method: 'POST', credentials: 'include' });
if (!r.ok) { location.assign('/login'); throw new Error('reauth'); }
accessToken = (await r.json()).access_token;
}
2つ目は、リフレッシュトークンがいつでも使えなくなりうることを忘れる点です。Googleは、6か月使われなかった場合や、利用者がアクセスを取り消した場合などに働かなくなるとし、アカウントとクライアントIDの組ごとに100個という上限もあり、超えると古いものから無効になります。*6 更新でinvalid_grant(トークンが無効・期限切れ・取り消し済みであるか、別のクライアントに発行されたものであることを表すエラー)が返ったら、再試行を繰り返さずに再ログインへ案内します。
3つ目は、ログアウトしても認可サーバー側でトークンが生きたままになる点です。画面から消すだけでなく、RFC 7009のトークン失効の窓口にリフレッシュトークンを送ります。RFC 7009は、リフレッシュトークンを失効させたときは同じ認可に基づくアクセストークンも無効にすべきだとしています。*9 Microsoftは古いリフレッシュトークンを自動では無効にしないので、新しいものを受け取ったら古いものは消すよう案内しています。
4つ目は、トークンの長さを決め打ちすることです。RFC 6749はトークンの大きさを定めておらず、クライアントは長さを仮定すべきでないとしています。Googleは、長さの上限をアクセストークンで2048バイト、リフレッシュトークンで512バイトとしています。*6 データベースの列の長さは、使う認可サーバーが公表している上限に合わせて決めます。
外部に委託するときに確認しておきたい点
認可の仕組みを外部の開発会社と作るときは、設計書に次の点が書かれているかを確かめます。
- クライアントの種類ごとの、2つのトークンの期限(使われない期限と、最初の発行からの上限)とその理由
- 保存場所(ブラウザに渡すか、BFFを置くか、端末のどの領域に置くか)
- ローテーションを使うかどうかと、同時に更新が走ったときの扱い
- ログアウト、パスワード変更、アカウント停止のときにトークンを失効させる手順
- アクセスログやエラー通知にトークンが出ないこと
受け入れでは動きで確かめます。期限を短くした検証環境で、期限切れからの更新、複数タブでの同時更新、失効後の再ログイン、入れ替え済みの古いリフレッシュトークンの拒否を試験の項目に入れておくと、本番で初めて気づく事態を減らせます。Keycloakなどの認証基盤を使う場合は、選んだ設定値も記録に残してもらいます。組み立て方は「KeycloakでSSO認証基盤を外注構築」も参考になります。
まとめ:トークンの設計で確かめたい3つの点
アクセストークンとリフレッシュトークンを設計するうえで、確かめておきたい点は3つに整理できます。第一に、2つのトークンを提示する相手を分け、アクセストークンの期限を短くすること。第二に、リフレッシュトークンに使われない期限と最初の発行からの上限を設け、ローテーションなどで漏えいに備えること。第三に、クライアントの種類ごとに保存場所を決め、ログアウト時の失効まで試験することです。この3点を踏まえておけば、「盗まれたトークンで、いつまでもAPIを使われ続けた」という事態を避けやすくなります。認可の設計や既存の仕組みの見直しに迷いがあれば、外部の手を借りるのも一つの選択肢です。
よくある質問
クライアントクレデンシャルの方式でも、リフレッシュトークンは発行されますか
原則として発行されません。RFC 6749は、クライアントが自分の資格情報でアクセストークンを受け取るこの方式では、リフレッシュトークンを含めるべきではないとしています。サーバー同士の連携では、期限が切れたら同じ資格情報で新しいアクセストークンを取り直します。
アクセストークンの期限が切れる前に更新してもよいですか
問題ありません。RFC 6749も、期限切れが分かっているならAPIを呼ぶ前にリフレッシュトークンで取り直す流れを示しています。受け取った時刻とexpires_inから切れる時刻を計算し、サーバー間の時刻のずれを見込んで少し早めに更新すると、エラーを受けてからの再送を減らせます。
利用者がパスワードを変えたとき、発行済みのトークンはどうなりますか
認可サーバーの設定しだいです。RFC 9700は、パスワード変更や認可サーバーでのログアウトといった出来事を受けて、リフレッシュトークンを自動で失効させてよいとしています。使う製品がどう振る舞うかを確かめ、失効させたい場面を設計書に書いておきます。
アクセストークンとリフレッシュトークンの設計のご相談
元請(プライムベンダー)として、認可の設計と実装から、システムの保守・運用までご提案します。
Remoguとリラシクなら、認証・認可の設計や実装に加わるITエンジニアも探せます。
Remoguは、リモート前提で全国から即戦力のITプロ人材を調達するサービスです。リラシクは、扱う求人がすべてリモートワークのITエンジニア専門転職エージェントです。どちらもLASSICが運営しています。
出典
- *1 参考:IETF「RFC 6749 The OAuth 2.0 Authorization Framework」(https://www.rfc-editor.org/rfc/rfc6749)。出典:1.4節(アクセストークン)・1.5節(リフレッシュトークンと図2)・4.4.3節・5.1節(expires_inの例3600、Cache-Control: no-store、トークンの大きさ)・5.2節(invalid_grant)・6節(リフレッシュトークンの置き換え)・10.3節・10.4節を参照(2026年10月確認)
- *2 参考:IETF「RFC 6750 The OAuth 2.0 Authorization Framework: Bearer Token Usage」(https://www.rfc-editor.org/rfc/rfc6750)。出典:5.3節の推奨事項(1時間以内の短い期限、ページのURLで渡さない、Cookieに平文で保存しない)を参照(2026年10月確認)
- *3 参考:IETF「RFC 9700 Best Current Practice for OAuth 2.0 Security」(2025年1月)(https://www.rfc-editor.org/rfc/rfc9700)。出典:2.2.2節と4.14節(リフレッシュトークンの保護、パブリッククライアントへの送り手との結び付けまたはローテーションの要求、使われないトークンの失効、パスワード変更やログアウトでの失効、トークンの完全性)を参照(2026年10月確認)
- *4 参考:Microsoft Learn「Access tokens in the Microsoft identity platform」(https://learn.microsoft.com/en-us/entra/identity-platform/access-tokens)。出典:Token lifetime の項(既定の有効期間は60〜90分の間でランダム、平均75分。ばらつかせる理由)を参照(2026年10月確認)
- *5 参考:Microsoft Learn「Refresh tokens in the Microsoft identity platform」(https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens)。出典:Token lifetime の項(SPAは24時間、それ以外は90日。古いリフレッシュトークンを自動では無効にしない)を参照(2026年10月確認)
- *6 参考:Google for Developers「Using OAuth 2.0 to Access Google APIs」(https://developers.google.com/identity/protocols/oauth2)。出典:Refresh token expiration の項(6か月未使用、テスト中の外部向けアプリは7日、アカウントとクライアントIDごとに100個の上限)と Token size の項(アクセストークン2048バイト、リフレッシュトークン512バイト)を参照(2026年10月確認)
- *7 参考:IETF「OAuth 2.0 for Browser-Based Applications」(Internet-Draft draft-ietf-oauth-browser-based-apps-27)(https://datatracker.ietf.org/doc/draft-ietf-oauth-browser-based-apps/)。出典:策定中の文書。6.1節(BFF)・6.3.2.3節(リフレッシュトークンの期限の上限とアクセストークン10分・リフレッシュトークン8時間の例)・8.5節(localStorageの性質)を参照(2026年10月確認)
- *8 参考:IETF「RFC 6819 OAuth 2.0 Threat Model and Security Considerations」(https://www.rfc-editor.org/rfc/rfc6819)。出典:5.1.5.3節(短い期限の効果と注意点)・5.1.6節(アクセストークンを一時的なメモリに置く)・5.2.2.3節(ローテーションとクラスター構成での注意)を参照(2026年10月確認)
- *9 参考:IETF「RFC 7009 OAuth 2.0 Token Revocation」(https://www.rfc-editor.org/rfc/rfc7009)。出典:2.1節(リフレッシュトークンを失効させたときの関連するアクセストークンの扱い)を参照(2026年10月確認)