セッションベース認証とトークンベース認証の違いを分かりやすくまとめてみる
Web アプリケーションにおける認証方法は複数存在しますが、その中でもよく用いられるのがセッションベース認証とトークンベース認証です。
今回はこれらの違いについて説明したいと思います。
セッションベース認証
セッションベース認証では、下図のようにして認証を行います。
具体的な流れを次に示します。
- ユーザーの認証を経て、サーバーでセッション ID を発行します。このときサーバーではセッション ID とユーザー情報を対応づけておきます。
- サーバーはブラウザにセッション ID を返します。
- ブラウザは Cookie にセッション ID を保存します。
- ブラウザは保存しておいたセッション ID を含めた形でサーバーにリクエストを送ります。
- サーバーはリクエストに含まれるセッション ID を確認し、対応するユーザー情報を取得します
- サーバーはそのユーザーがアクセス可能なリソース (サーバー側の実装でどのユーザーがどのリソースにアクセス可能かを決めておきます) を返します。
ログアウトした場合は、ブラウザでセッション ID を別の値に更新しつつ、サーバーでもセッション ID とユーザー情報の対応を破棄します。
これで元々のセッション ID を用いてユーザー情報やリソースにアクセスすることはできなくなるわけです。
トークンベース認証
一方、トークンベース認証は、下図のようにして認証を行います。
具体的な流れを次に示します。
- ユーザーの認証・認可を経て、サーバーでアクセストークンを発行します (セッションベース認証と異なり、アクセストークンとユーザー情報は対応づけられません)。アクセストークンには、有効期限やそのトークンでアクセス可能なリソースの範囲 (スコープと呼ばれる) などの情報が含まれています。またアクセストークンは基本的に改ざんが困難な JWT 形式になっています。
- サーバーはブラウザにアクセストークンを返します。
- ブラウザは Cookie などにアクセストークンを保存します。
- ブラウザは保存しておいたアクセストークンを含めた形でサーバーにリクエストを送ります。
- サーバーはリクエストに含まれるアクセストークンを検証し、改ざんがされておらず有効期限などにも問題がないことを確認します。
- サーバーはそのトークンでアクセス可能なリソース (サーバー側でどの “スコープ” がどのリソースにアクセス可能かを決めておきます。どの “アクセストークン” がどのリソースにアクセス可能か、ではない点にご留意ください) を返します。 [1]
セッションベース認証とトークンベース認証の違い
ステートフルなセッションベース認証、ステートレスなトークンベース認証
両者の最も大きな違いは、セッションベース認証がサーバーに認証のための情報 (セッション ID とユーザー情報の対応) を持たせておくのに対し、トークンベース認証はサーバーにそうした情報を持たせずトークンの検証のみによって認証を行う点です。
これはつまりセッションベース認証はステートフルであり、トークンベース認証はステートレスであるということです。
セッションベース認証がステートフルな通信を実現できるというメリットを持つ一方で、トークンベース認証は (サーバーに認証のための情報を持つ必要がないため) ユーザーが増加した時のサーバー負荷がセッションベース認証よりも少なく、よりスケーラブルなシステムを実現できるというメリットを持ちます。
セッション ID を無効化できるセッションベース認証、アクセストークンを無効化できないトークンベース認証
これはトークンベース認証の最大のデメリットですが、基本的にアクセストークンは無効化できません。
この意味を理解するために、トークンベース認証におけるログアウトを考えてみましょう。
トークンベース認証でログアウトしたとき、サーバーは認証のための情報を持っていないため、単純にブラウザに保存していたアクセストークンを破棄します。
しかし前述のとおり、トークンベース認証はトークンの検証のみによって認証を行うため、ブラウザで破棄されたとてアクセストークンそのものは依然有効なわけです。
そのため、もしもそのアクセストークンが悪意あるユーザーの手に渡っていた場合、正規のユーザーがログアウトした後でも、悪意あるユーザーはリソースにアクセスできてしまうのです。
一方セッションベース認証であれば前述の通り、ログアウト後に元々のセッション ID を用いてユーザー情報やリソースにアクセスすることはできません。
アクセストークンの流出リスクへの緩和策
一応、アクセストークンの流出リスクへの緩和策が存在するので、代表的なものを紹介しておきます (緩和策であり完全な解決策ではない点にご留意ください)。
1 つ目が、アクセストークンの有効期限を短く設定することです。有効期限を短くすることでトークンが流出したときの被害を最小限に抑えようというシンプルな発想です。
ただ単純にトークンの有効期限を短くするだけではユーザーに求める認証回数が増えユーザービリティが損なわれてしまうため、アクセストークンを新しいものに取り替える機能をもつトークン (= リフレッシュトークンと呼ばれており、アクセストークンよりも有効期限が長く設定されています) を活用して、セキュリティとユーザビリティのバランスを取ることが多いです。
2 つ目が、サーバーにアクセストークンのブラックリストを持たせておく方法です。
流出の恐れがあるアクセストークンをブラックリストに登録しておき、トークンを検証するタイミングでブラックリストの確認も行うようにします。
ただしトークンの検証のみで認証ができるというトークンベース認証の利点が損なわれ、スケーラビリティが低くなってしまうというデメリットがあります。
セッションベース認証とトークンベース認証のユースケース
通常の Web アプリケーションではセッションベース認証を用いることが多いです。
一方、API ではトークンベース認証を用いることが多いように思います。特に Stripe API や Gmail API など、不特定多数のクライアントを認証する必要がある API では、スケーラビリティの観点からトークンベース認証が使われることが多いです。
セッションベース認証とトークンベース認証を併用するパターン
あまり一般的ではないと思いますが、セッションベース認証とトークンベース認証の併用するパターンもあり得ると思います。
例えば下図のように、特定の SPA のために作成された API があり、トークンベース認証を行う認可サーバーを別で立てているようなケースでは、二つの認証方法を併用するケースがあり得ます。
このような構成の場合、SPA は認可サーバーで発行されたアクセストークンを用いて API にリクエストを送ることになりますが、今回の API は不特定多数のクライアントを認証する必要はなく、ステートレスである必要性もさほど高くありません。
また前述の通り、セッションベース認証には、ステートフルな通信ができる、セッション ID が流出した場合でも無効化ができるというメリットがあります。
こうしたケースでは二つの認証方法を併用し、セッションベース認証を行った上で、トークンベース認証を行います。
こうしておけばログアウトによってセッション ID を無効化してしまえば、例えアクセストークンが有効であっても、セッションベース認証の時点ではじくことができるというわけです。
まとめ
今回は Web アプリケーションにおける認証方法の中でも特に重要な「セッションベース認証」と「トークンベース認証」についてまとめてみました。
この記事が少しでも理解の助けになれば幸いです。
内容に間違いがあれば、コメントでご指摘いただけると嬉しいです。
いいね、フォローもぜひお願いします 🐳🐣🐙
-
これは個人的な考えですが、この仕組みからするに、トークンベース認証で実際に行っているのは「トークンの認証 (検証)」であって「ユーザーの認証」ではないのかなと思っています。
なので個人的には「トークンベース “認可” (トークンの権限を認めてリソースへのアクセスを許可する)」といった方がしっくりくるのですが、一般的には「トークンベース “認証”」という言葉が広く使われています。
その理由を考えるに、1 つ目は実際の運用では (その是非はさておき) トークンにユーザー ID を含めておきサーバー側でそのユーザー ID を元にユーザー情報を取得するような使い方をすることがままあるため、2 つ目は言葉の使い方として一般に、許可証を発行する行為を認可、発行した許可証を検証する行為を認証ということがあるためかなと思っています。
なお一方で、セッションベース認証では途中でセッション ID がユーザー情報に紐付くため「ユーザーの認証」を行っていると言えると思っています。 ↩︎
Discussion
と記載ありますが、user id を token に含めることには何か問題があるのでしょうか?
以下 GPT の回答です
トークンに User ID を含めること自体は一般的な手法ですが、いくつかのセキュリティリスクや設計上の懸念があるため、慎重に取り扱う必要があります。主な問題点を挙げてみます。
⸻
トークンの改ざんリスク
• 署名されていないトークン(例えばプレーンなJSON形式)にUser IDを含めると、悪意ある第三者がトークンを改ざんし、別のユーザーIDに置き換えて不正アクセスを試みる可能性があります。
• これを防ぐために、一般的には JWT (JSON Web Token) のような署名付きのトークンを使用し、改ざんを検知できるようにします。
情報の漏洩リスク
• トークンが漏洩した場合、User ID も一緒に流出することになります。
• もしUser IDが 単純な連番 (例: 1234) や メールアドレス だった場合、攻撃者にとってユーザー情報を推測しやすくなる可能性があります。
プライバシーの懸念
• User IDのフォーマットによっては、個人情報に関連するデータ(例えば社員番号やメールアドレス)がトークンに含まれることになり、情報漏洩時の影響が大きくなります。
• トークンは通常 クライアント側でも確認できる(特にJWT)ので、過剰な情報を含めるとプライバシーリスクが高まります。
サーバーのステートレス性が損なわれる可能性
• 一部のシステムでは、トークンにUser IDを含めることで、サーバー側で追加のデータベース問い合わせを行わずにユーザー識別ができます。
• しかし、トークンだけではユーザーの状態を完全に管理できないため、結局サーバー側で情報を持つ(セッション的な動きになる)ケースもあり、トークンベース認証の ステートレス性 のメリットが薄れる場合があります。
トークンの肥大化
• JWTでは、User IDに加えて追加の情報(権限情報、発行時間、有効期限など)が含まれるため、トークンのサイズが大きくなる可能性があります。
• 特にモバイル環境や帯域制限のある通信では、トークンの肥大化がパフォーマンスに影響を与えることがあります。
⸻
では、どうするべきか?
✅ 最小限の情報だけを含める
• User ID を直接含めるのではなく、トークン固有の識別子 (例: jti Claim) を使ってサーバー側で照合する 方法が安全。
• 例: jti: "a1b2c3d4e5f6" というUUIDを発行し、データベース側でUser IDとマッピングする。
✅ トークンを暗号化 or 署名付きにする
• JWTを使用する場合は、HMAC-SHA256 / RS256 / ES256 などで署名して改ざんを防ぐ。
• 必要に応じて JWE (JSON Web Encryption) を使ってトークンのペイロードを暗号化する。
✅ 短い有効期限 + リフレッシュトークンを使う
• アクセストークンは 短い有効期限 (例: 15分〜1時間) にして、万が一漏洩してもリスクを最小限にする。
• 代わりに、長期間使えるリフレッシュトークンを使ってアクセストークンを再発行する仕組みを導入する。
✅ スコープを適切に設定する
• ユーザーIDを含める場合は、トークンがどの範囲のリソースにアクセスできるのか スコープ を明確にする。
• 例えば、scope: ["read:user", "write:posts"] のように制限をつける。
⸻
結論
User ID をトークンに含めること自体は一般的な実装ですが、適切なセキュリティ対策をしないと、改ざん・情報漏洩・プライバシー問題が発生するリスクがあります。
そのため、安全な方法として トークン固有の識別子 (jti) を使う、トークンを署名付きにする、短い有効期限を設定する などの対策を検討するのがベストです。