はじめに
そもそも「トークン」とは?
ログインの仕組みを考えるとき、まず「トークン」という言葉が何を指すのかを押さえておきましょう。
用語メモ:トークン(token)とは?
ここでいうトークンは、ログインに成功したことを証明する**電子的な「引換券」や「入館証」**のようなものです。
窓口(サーバー)でログインすると、代わりにこの券を渡され、以降はその券を見せることで「私はさっきログインした本人です」と伝えられます。
毎回パスワードを見せなくてよくするための仕組み、とイメージしてください。
このシリーズの第4回では、その券の中身が「JWT(ジョット)」という形式で書かれていることを学びました。今回はその券が3種類あるという話です。
用語メモ:JWT(JSON Web Token)とは?
トークンの中身を書くための決まった書式のひとつ。
中身は暗号化されておらず、誰でも読める(ただし勝手に書き換えると「署名」で見破られる)というのが第4回のポイントでした。
「読めるけど改ざんはできない券」と覚えておけばOKです。
この記事でわかること
- 3種類のトークンがそれぞれ「何を証明する券」なのか
- ID トークンで API を守ってはいけない理由
- リフレッシュトークンで「ログインし直さずに済む」仕組みと、その限界
- ログアウトしたのにトークンが使えてしまう理由
この記事の前提
第3回(OIDC)と第4回(JWT)を読んでいると理解しやすいですが、読んでいなくても大丈夫なように、必要な用語はその都度「用語メモ」で補います。
- 第3回「OpenID Connect(OIDC)とは?」
- 第4回「JWTとは?」
本編
登場人物を先に整理する
トークンの話は「誰が誰に何を渡すか」が分かりづらいので、先に登場人物を日常語で押さえます。
用語メモ:3人の登場人物
- クライアント … あなたが使うアプリ本体(スマホアプリ、ブラウザで動くWebアプリなど)。券を受け取る人。
- 認可サーバー(Authorization Server) … 券を発行する窓口。AWS では Cognito がこの役目をします。
- API(Resource Server) … 券を見せて使うサービスの裏側(例:注文一覧を返すサーバー)。券を見て「この人に見せてよいか」を判断する人。
以降、この「アプリ本体」「窓口(Cognito)」「API」の3人が出てきます。
なぜトークンは3種類もあるのか
「1種類の券で全部済ませればラクなのに、なぜ3つに分けるの?」という素朴な疑問から入ると分かりやすいです。分ける理由は主に3つあります。
-
「誰か」と「何をしてよいか」は別の話だから
「あなたが田中さん本人だ」ということと、「田中さんは注文を見てよい」ということは、別々の情報です。これを1枚の券に混ぜると境界が曖昧になります。用語メモ:認証(AuthN)と認可(AuthZ)
- 認証(にんしょう) … 「あなたは誰か?」を確かめること。ログインそのもの。
-
認可(にんか) … 「あなたは何をしてよいか?」を判断すること。権限のチェック。
名前が似ていて紛らわしいですが、「認証=誰か」「認可=何をしてよいか」とセットで覚えると混乱しません。
-
持たせたい寿命が正反対だから
後で詳しく書きますが、ある券は「盗まれたときの被害を小さくしたいのですぐ切れてほしい」、別の券は「何度もログインさせたくないので長持ちしてほしい」。要求が真逆なので、1枚にまとめると両立できません。 -
渡す相手が違うから
ある券はアプリ本体が自分で読むだけ、ある券は API に渡す、ある券は発行元(Cognito)にしか渡してはいけない。渡す相手が違えば扱い方も変わるので、混ぜないほうが安全です。
3つのトークンの役割(まず全体像)
細かい話に入る前に、3種類を1枚の表で見比べます。ここは「へぇ、こう違うんだ」と眺めるだけでOKです。
| ID トークン | アクセストークン | リフレッシュトークン | |
|---|---|---|---|
| ひとことで言うと | 誰がログインしたかの証明 | 何をしてよいかの証明 | 券を再発行してもらう権利 |
| 主な渡し先 | アプリ本体(自分で読む) | API | 窓口(Cognito)だけ |
| 寿命 | 短い | 短い | 長い |
| 誰がチェックする | アプリ本体 | API 側 | 発行元だけ |
次の図で「どの券をどこに渡すか」を見ると、渡し先の違いが一目で分かります。
ポイント:
アクセストークンだけが API に渡ります。
ID トークンとリフレッシュトークンは API には渡しません。
この違いがこの記事のいちばん大事なところです。
ID トークン — 「誰がログインしたか」の証明
ID トークンは、アプリ本体が「ログインできた」「この人は誰か」を知るための券です。
- ユーザー名やアイコンを画面に表示する、といった用途に使います。
- API に見せて「入っていいか」を判断させる用途では使いません(理由は次で説明します)。
中身の例を見てみましょう(Cognito の場合)。今は細部を暗記する必要はなく、メールアドレスなど「その人の情報」が入っている点だけ見てください。
{
"sub": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"cognito:username": "my-test-user",
"email": "my-test-user@example.com",
"aud": "xxxxxxxxxxxxexample",
"token_use": "id",
"exp": 1676316377
}
用語メモ:
token_useとは?
Cognito の券に入っている「この券の種類」を表す印です。
ID トークンならid、アクセストークンならaccessと書かれています。
あとで「券を取り違えていないか」を確かめるときの目印になります。
用語メモ:
aud(audience)とは?
「この券は誰宛て?」を表す欄です。ID トークンのaudにはアプリ(クライアント)のIDが入ります。
つまり ID トークンはアプリ本体宛ての券であって、API 宛てではない、ということです。
アクセストークン — 「何をしてよいか」の証明
アクセストークンは、API に「私はこれをしてよい権限を持っている」と示すための券です。API へのリクエストのときに、次のように付けて送ります。
GET /orders HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJraWQi... (アクセストークン)
中身には、その人の属性(メールなど)ではなく、権限に関する情報が入ります。
{
"sub": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"cognito:groups": ["testgroup"],
"client_id": "xxxxxxxxxxxxexample",
"token_use": "access",
"scope": "phone openid profile email",
"exp": 1676317451
}
ID トークンには email があったのに、アクセストークンには(Cognito では標準では)入っていない点に注目してください。
ID は「誰か」、アクセスは「何をしてよいか」 を答える券なので、載っている情報が違うのです。
用語メモ:Bearer トークンとは?
Authorization: Bearer ...の「Bearer(ベアラー)」は「持参人」という意味。
その券を持っている人なら誰でも通してしまう方式です。
改札の切符と同じで、落とした切符を拾った人でも改札を通れてしまう、というイメージ。
だから「盗まれたら悪用される=すぐ切れるようにしておく(短命化)」が最大の防御になります。
なぜ ID トークンで API を守ってはいけないのか
ここが最初のつまずきポイント。
- ID トークンには 「何をしてよいか」の情報(権限)が入っていません。API はそれを見ても許可の判断ができません。
- ID トークンの
aud(宛先)はアプリ本体であって API ではありません。つまり「API 宛てではない券」を無理やり API に見せている状態になります。
たとえるなら、社員証(あなたが誰かを示す)を「立ち入り許可証」の代わりに使おうとするようなものです。
社員証で本人確認はできても、「サーバー室に入ってよい」という許可は別の証明が必要です。
API を守るのは、必ずアクセストークンの役目です。
リフレッシュトークン — 「券を再発行してもらう権利」
アクセストークンはすぐ切れます。切れるたびにログインし直すのは面倒です。そこで登場するのがリフレッシュトークンです。
リフレッシュトークンは、**アクセストークンが切れたときに、パスワードを入れ直さずに新しい券をもらうための「引換券」**です。
- 長持ちする券なので、保管の慎重さがいちばん求められます(盗まれると長い間悪用されうる)。
- ローテーションという仕組みが推奨されます。
用語メモ:ローテーションとは?
券を更新するたびに、古いリフレッシュトークンを無効にして新しいものに差し替えること。もし古い券が盗まれて使われても、「もう無効なはずの券が使われた」と気づいて遮断できます。使い捨ての整理券を毎回引き直すイメージです。
新しい券をもらうときのやり取りはこんな形です(今は眺めるだけでOK)。
POST /oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&client_id=xxxxxxxxxxxxexample&refresh_token=eyJjdHki...
{
"access_token": "eyJraWQiOi...",
"id_token": "eyJraWQiOi...",
"token_type": "Bearer",
"expires_in": 3600
}
ローテーションが有効なときは、この応答に新しいリフレッシュトークンも一緒に入っていて、使った古い券は無効になります。
大事な注意:リフレッシュトークンがあっても「永久にログイン状態」ではありません。 これにも最大寿命があり、そこを超えれば結局ログインし直しになります。
3つの券がどう連携するか(流れで見る)
「切れたら更新する」という流れを時間順に追うと、3つの券の連携が見えてきます。
用語メモ:401 とは?
API が「その券では通せません(認証・トークンに問題あり)」と返すときのエラー番号です。券が切れていたり、券を取り違えていたりすると出ます。
Cognito での具体的な寿命(数字は眺めるだけでOK)
「短い」「長い」だけだとイメージしづらいので、AWS の Cognito での実際のデフォルト値を挙げます。細かい範囲は今は暗記不要です。
| 券 | デフォルトの寿命 | 設定できる範囲 |
|---|---|---|
| ID トークン/アクセストークン | 1時間 | 5分〜1日 |
| リフレッシュトークン | 30日 | 60分〜10年 |
有効期限はどう決める?
「短ければ短いほど安全」ではありません。
安全性と使いやすさ(UX)のバランスで決めます。
| 観点 | 考え方 |
|---|---|
| アクセストークン | 短くすると、盗まれても悪用できる時間が短くなる。数分〜1時間が一般的 |
| リフレッシュトークン | 「どのくらいの頻度なら再ログインを我慢してもらえるか」で決める |
| 短くしすぎる副作用 | 更新の頼みごとが増え、窓口(Cognito)への通信が増えて重くなる |
つまり、アクセストークンは「盗まれたときのリスク」から、リフレッシュトークンは「使いやすさ」から決める、と考える軸が分かれます。
ログアウトしたのにトークンが使えるのはなぜ?
JWT でいちばん誤解されるところです。
「ログアウトしたんだから、もう無効でしょ?」と思いますよね。ところが、そうとは限りません。
理由:JWT は自己完結した券です。署名が正しくて、まだ期限(exp)が切れていなければ、わざわざ発行元(Cognito)に問い合わせなくても「有効」と判断されます。だから、アプリが手元の券を捨てても、そのコピーがどこかに残っていれば、期限が切れるまで使えてしまうのです。
たとえ:一度発行した「入館証」を回収せずに期限だけ書いておくと、本人が「もう使いません」と言っても、コピーを持っている人は期限までゲートを通れてしまう、というイメージです。
現実的な対策は、次の順で考えます。
- アクセストークンを短命にする(いちばん現実的。悪用できる時間=有効期限に抑える)。
- リフレッシュトークンを無効化(revoke)する(新しいアクセストークンを取れなくして、更新の道を断つ)。
- どうしても即座に無効化したい場合は、券を1枚ずつ問い合わせて確認する仕組みを入れる。ただし、これは JWT の「自己完結で速い」という長所を捨てることになり、コストがかかります。
用語メモ:revoke(リボーク)とは?
券を「無効にする(取り消す)」こと。とくにリフレッシュトークンを revoke すると、以降は新しいアクセストークンを取り直せなくなります。
401 が出たときの調べ方(トラブル時)
券の使い分けを間違えると、たいていは API 側の 401 として現れます。どこから疑うかの順番を図にしました。初級者はまず「一番上の分岐」だけ覚えれば十分です。
-
最初に見るのは
token_use。 ID トークンを API に送ってしまう事故が、いちばん多いです。 - 次に
exp(切れていれば更新で解決)。それでもダメなら鍵や権限の問題を疑います。
よくある誤解
| よくある誤解 | 実際は |
|---|---|
| 「ID トークンで API を守れる」 | 守れません。権限(scope)を持たず、宛先(aud)もアプリ向けだからです。API を守るのは必ずアクセストークン。 |
| 「アクセストークンにメールアドレスが入っているはず」 | Cognito では標準では入りません。属性が必要なら ID トークンなどを使います。 |
| 「リフレッシュトークンがあれば永久にログイン状態」 | 最大寿命があります。更新しても寿命は延びません。 |
| 「ログアウト=トークン無効化」 | 手元で券を捨てるだけでは無効になりません。期限が切れるか、revoke するまで有効です。 |
まとめ
| 観点 | 押さえるポイント |
|---|---|
| 3つの役割 | ID = 誰かの証明、アクセス = 何をしてよいかの証明、リフレッシュ = 再発行の権利。 渡す相手も、チェックする人も違う |
| API の保護 | API を守るのは必ずアクセストークン。 ID トークンは API に送らない |
| ログアウト | すぐ無効にならないのは、JWT が「自己完結した券」だから。現実解は「短命化 + リフレッシュの revoke」 |
| デフォルト寿命 | Cognito では ID/アクセス = 1時間、リフレッシュ = 30日 |
参考リンク
- OpenID Connect Core 1.0(ID Token)
- RFC 6749(OAuth 2.0)/ RFC 6750(Bearer Token Usage)
