ソフトウェアアーキテクチャ

認証・セッション設計 ― サーバセッション vs JWT ― 生成AI時代のアーキテクチャ超入門

認証・セッション設計 ― サーバセッション vs JWT ― 生成AI時代のアーキテクチャ超入門

本記事について

当サイトを閲覧いただきありがとうございます。 本記事はシリーズ『生成AI時代のアーキテクチャ超入門』の「ソフトウェアアーキテクチャ」カテゴリ最終記事(第7弾)として、サーバ側の認証・セッションについて解説する記事です。

本記事の問いは「ログイン後のセッションをどう持つか」サーバセッション vs JWTOAuth 2.0/OIDC・Cookie属性の安全設定まで扱い、「同一ドメインはCookie、横断はJWT」という実務判断軸を示します。

扱う扱わない(→別記事)
サーバセッション・JWT・OAuth・Cookieサーバ設定認証強度(MFA / Passkey / IDaaS)・認可(IAM)・ブラウザ防御(XSS / CSP)

このカテゴリの他の記事

認証と認可の違い

アプリにログイン機能を実装するとき、しばしば混同されるのが認証(Authentication)と認可(Authorization)です。この2つは目的が全く異なるため、設計段階で明確に分けて考える必要があります。

認証「あなたは誰ですか」を確認する処理で、パスワードやPasskeyによって本人確認を行います。認可「あなたは何ができますか」を決める処理で、ログイン済みの利用者に対して「管理画面を表示してよいか」「このデータを編集してよいか」といった権限を判定します。

用語内容英語(略称)
認証誰なのかを確認するAuthentication(AuthN)
認可何ができるかを決めるAuthorization(AuthZ)

「ログインできたから管理者操作もできる」典型的な混同。認証と認可は別物として設計します。

セッション管理の2大方式

認証後、ユーザーが再度ログインせずにAPIを使い続けられるようにする仕組みをセッション管理と呼びます。方式は大きく「サーバ側に状態を保持する方式」「クライアント側に持たせる方式」の2つに分かれます。

方式状態の保持場所特徴
サーバセッション(Cookie)サーバ側(Redis等)即時失効可能・実績豊富
JWT(トークン)クライアント側ステートレス・スケール容易

どちらが優れているということはなく、「同一ドメインの普通のWebアプリならサーバセッション」マイクロサービス横断や外部連携を含むAPIならJWT、というのが使い分けの定石です。

サーバセッション方式

サーバセッションは、ログイン成功時にサーバーがランダムなセッションIDを発行し、クライアントのCookieに保存させる方式です。以降のリクエストはこのCookieを携えてサーバーに届き、サーバーはセッションIDから Redis 等のストアを参照してユーザー情報を取り出します。

古くから使われている方式で、即時失効が可能(Redisから消せばセッション無効)、情報漏洩時の被害を局所化しやすい、ライブラリが成熟しているという強みがあります。一方、セッションストアを別途運用する必要があり、サーバが横に並ぶ構成(スケールアウト)では全台でストアを共有する必要があります。

強み弱み
即時失効が可能(ログアウト処理が簡単)セッションストアが必要
実績豊富・ライブラリ成熟ステートフル(サーバ側に状態あり)
漏洩時の被害を局所化しやすいスケール時に共有が必要

同一ドメインの一般的なWebアプリ・SPAなら、サーバセッションで十分かつ安全です。

JWT(JSON Web Token)方式

JWT は、ユーザー情報そのものを署名付きのトークンに詰めてクライアントに渡す方式です。サーバーは毎回トークンの署名を検証するだけで認証できるため、サーバー側に状態を持たない(ステートレス)のが最大の特徴です。

マイクロサービスが複数立ち並ぶ構成では、各サービスが独立して認証処理できる強みがあります。一方で即時失効が困難(トークンは期限まで有効)、秘密鍵が漏れると全ユーザー偽装可能、ペイロードは誰でも Base64 でデコードできるといった注意点があります。

Header.Payload.Signature
─────  ────────  ─────────
アルゴ  ユーザー  改竄検知の
リズム   情報      ための署名

JWTの罠

JWTを採用する場合、以下の落とし穴を理解しておく必要があります。特に「失効の困難さ」はJWTの根本的な性質で、回避策には別途仕組みが必要です。

  • 失効できないJWTは期限まで有効なので、漏洩しても即座に無効化できない。対策:短命のAccess Token + httpOnly CookieにいれたRefresh Tokenの組み合わせが定石
  • 秘密鍵漏洩は致命的:署名秘密が漏れると、全ユーザーになりすましたトークンを作られる
  • ローカルストレージに保存するとXSSに弱いXSS(Cross-Site Scripting、悪意あるスクリプトを埋め込む攻撃)で簡単に盗まれる。httpOnly Cookieに保存するのが安全
  • ペイロードに機密情報を入れない:Base64エンコードは暗号化ではありません。誰でもデコードできる

「Access Token(短命)+ Refresh Token(長命・httpOnly)」が現代のJWT運用の定石です。

OAuth 2.0 / OIDC

OAuth 2.0「認可の委譲」を行うためのプロトコルです。「このアプリに Google Drive の読み取り権限を渡す」のように、第三者アプリにAPIアクセス権限を渡す仕組みとして広く使われています。

OpenID ConnectOIDC)はOAuthを土台にして認証を標準化した拡張で、「Googleでログイン」などの機能はOIDCで実現されています。

これらは標準化されたプロトコルなので、自前で実装せず Auth0 / Firebase Auth / Cognito / Okta などの認証サービスに委譲するのが現代の主流です。自前実装は脆弱性のリスクが高く、多要素認証Passkey対応まで含めると運用負荷が大きくなります。

プロトコル役割
OAuth 2.0第三者アプリにAPIアクセス権限を委譲する
OpenID Connect(OIDC)OAuthを土台にした認証用の拡張プロトコル

代表例:Google / Apple / GitHub ログイン / 社内SSO(Okta, Auth0)

認証は外部サービスに委譲が標準。自前実装は避けるのが安全です。

OAuthの主要フロー

OAuthには用途別にいくつかのフローがあります。Web・モバイルアプリではAuthorization Code + PKCEが事実上の標準で、それ以外のフローを新規採用する場面はほとんどありません。

判断軸は「誰が何を守るか」です。Authorization Codeフローは認可コードをブラウザ経由で受け取り、サーバー側でトークンと交換する2段構えの仕組みで、トークンそのものがブラウザの履歴やURLに残らないため漏洩リスクが低く抑えられます。

これにPKCEを組み合わせることで、途中で認可コードを横取りされても攻撃者がトークンに交換できない仕組みになり、SPAやモバイルのような「秘密を保持できないクライアント」でも安全に使えます。

sequenceDiagram
    participant U as ユーザー
    participant C as クライアント<br/>(SPA/モバイル)
    participant A as 認可サーバ
    participant R as リソースサーバ<br/>(API)
    U->>C: ログイン操作
    C->>C: code_verifier 生成<br/>code_challenge = SHA256
    C->>A: 認可リクエスト<br/>+ code_challenge
    A->>U: ログイン画面
    U->>A: 認証情報入力
    A->>C: 認可コード(短命)
    C->>A: トークン交換<br/>code + code_verifier
    A->>A: code_verifier の<br/>SHA256 が code_challenge と一致するか検証
    A->>C: Access Token + Refresh Token
    C->>R: API呼び出し<br/>+ Access Token
    R->>C: APIレスポンス
フロー用途
Authorization Code + PKCE(Proof Key for Code Exchange、認可コード横取り対策)SPA・モバイル・Webアプリ(標準)
Client Credentialsサーバ間通信(ユーザーが介在しない)
Device CodeTV・CLI など入力困難な端末
Implicit Flow非推奨(セキュリティ上の問題あり)
Password Grant非推奨(パスワードを第三者に渡す設計)

新規実装ではPKCE付きAuthorization Code一択。古い情報源のImplicit / Password Grantは使いません。

ケース別の選び方

従来型Webアプリ(同一ドメイン)

サーバセッション(Cookie)。最も枯れた方式で、ログアウト処理も簡単。特別な理由がなければこれを既定に置きます。

SPA + API(同一ドメイン)

サーバセッション(Cookie)SPAだからJWT」は誤解。httpOnly Cookieで十分安全です。

マイクロサービス・横断認証

JWT + Refresh Token。ステートレスな性質がサービス間の独立性を高めます。

外部ログイン連携(Google・GitHub等)

OpenID ConnectOIDC)。Auth0 や Firebase Auth に委譲するのが現実的。

企業の社内システム(SSO必要)

OIDC + SSO基盤(Okta / Auth0 / Entra ID)。人事異動での権限変更も一元管理できます。

Cookieの設定

サーバセッションを使う場合も、JWTをCookieに入れる場合も、Cookie属性の設定が安全性を大きく左右します。これらはセキュリティインシデントの半数以上を防ぐ基礎対策です。

属性役割
HttpOnlyJavaScriptから読めないようにする(XSS対策)
SecureHTTPS通信でのみ送信する
SameSite=Lax または StrictCSRF(Cross-Site Request Forgery、利用者のログイン状態を悪用した偽リクエスト攻撃)を防ぐ
Domain / Path送信範囲を最小限に絞る
Max-Age / Expires有効期限を明示する

HttpOnly + Secure + SameSite=LaxはWebアプリの最低ラインです。これを欠くのは論外です。

実装イメージとしては Express / Hono / Next.js いずれも下記のような形が定番です。

// 推奨: Cookie で受け渡し(XSS から守られる)
res.cookie("session", token, {
  httpOnly: true,           // JS から読めない(XSS 対策)
  secure: true,             // HTTPS のみ送信
  sameSite: "lax",          // CSRF 対策
  maxAge: 60 * 60 * 1000,   // 1 時間
  path: "/",
});

// 非推奨: localStorage 保存(XSS 一発で漏洩)
localStorage.setItem("token", token);

JWT を採用する場合も、保管場所は localStorage ではなくHttpOnly Cookieにし、Refresh Token はさらに別 Cookie かサーバ側 KV ストアに分離します。「JWT=localStorage」という組み合わせは、2024年以降のセキュリティガイドラインでは事実上の禁則です。

セッション・トークン有効期限の数値Gate

※ 2026年4月時点の業界相場値です。テクノロジー・人材市場の変化で陳腐化するため、定期的にアップデートが必要です。

セッション設計は「なんとなく」で決めると必ず脆弱性を生むため、具体的な数値基準を最初に決めます。下記が業界の定番値です。

設定項目推奨値理由
Access Token(JWT)有効期限15分漏洩時の被害最小化
Refresh Token(httpOnly Cookie)有効期限14〜30日ユーザー利便性との両立
セッションCookie 有効期限30分〜24時間(業務次第)業務形態による
Session IDエントロピー128bit以上推測不能な長さ
JWT署名アルゴリズムRS256 / EdDSAHS256 は対称鍵、鍵配布に注意
JWT none アルゴリズム絶対に禁止2018年ライブラリ脆弱性で多発
Refresh Token Rotation有効化盗難検知で全セッション失効
CSRFトークンSameSite=Lax + CSRF token二重防御

JWTのアルゴリズムは RS256(RSA署名)または EdDSA を使い、noneアルゴリズムは絶対に許可しない。2018年に複数のJWTライブラリで none を許可する脆弱性が多発した過去があります。

Refresh Tokenは使用ごとに新しい値を発行(Rotation)し、古い値が再利用されたらセッション全失効という運用が現代の定石です。

セッション・トークン運用の鬼門

セッション実装で事故る典型パターンを整理します。どれもアカウント乗っ取り・成りすましに直結します。

禁じ手なぜダメか
JWTをlocalStorageに保存XSSで簡単に盗まれる。httpOnly Cookieが鉄則
Cookieに HttpOnly / Secure / SameSite を設定しないXSS・盗聴・CSRFの全てが成立する
「SPAだからJWT」の誤解でCookieセッションを避ける同一ドメインならCookieセッションの方が安全かつシンプル
JWTの失効設計なし漏洩時に無効化できない。短命Access + httpOnly Refreshが定石
JWTで none アルゴリズムを許可署名検証なしで偽造可能。2018年にライブラリ脆弱性が多発
OAuth Implicit Flow / Password Grant を新規採用2020年以降は非推奨。Authorization Code + PKCEが標準
Refresh Token Rotationなし盗難を検知できない。使用ごとに再発行が現代の定石
Session IDのエントロピーが弱い推測で乗っ取り。128bit以上の乱数が必須
Cookie属性をデフォルト任せ未設定だとSecureもHttpOnlyも効かない。明示設定必須
ログアウト時にCookie削除のみサーバ側Refresh Tokenが生き残る。失効API必須

認証方式そのもの(パスワード保存・MFAPasskey)の鬼門は別カテゴリ「セキュリティアーキテクチャ」を参照してください。本記事はセッション技術の鬼門に限定しています。

AI時代の視点

AI駆動開発(バイブコーディング)が前提になると、セッション実装は「AIが正しく書ける領域」と「書かせてはいけない領域」がきっぱり分かれます。

OAuth / OIDC / JWT のような標準化されたプロトコルに従う部分はAIが正確に書けますが、Cookie属性の明示・Refresh Token Rotation・失効APIのような「運用上の細かい設定」は落としがちです。

AI時代に有利AI時代に不利
OAuth / OIDC 標準フローの実装独自のトークン設計
短命Access Token + httpOnly Refresh Token長命・localStorage保存
Cookie属性をコードで明示(HttpOnly等)デフォルト任せ・暗黙の設定
SDK呼び出し(Auth.js・Clerk SDK等)自前のセッション管理

セッション技術でAIに任せるなら、「標準ライブラリやSDKの呼び出しに寄せる」のが安全です。Cookie属性・有効期限・Rotationの有無といった「数値や設定値」は、AIが書いたあとに人間が数値Gate表と突き合わせて確認するルーチンを組みます。

AI時代のセッションは「標準プロトコル + 明示設定」デフォルト任せが最大の事故源です。

よくある勘違い

  • SPAだからJWT → 同一ドメインなら Cookie セッションで十分です。JWTは運用上の難しさが増える。この誤解は根深い
  • JWTはlocalStorageに保存するもの」XSSで盗まれる典型パターン。httpOnly Cookieに入れるのが正解
  • JWTは失効できない前提で運用する」 → 短命Access Token + Refresh Token Rotation を組めば事実上の失効が可能です。設計の問題であってJWTの宿命ではない
  • 「Cookie属性はデフォルトで安全」 → HttpOnly も Secure も SameSite もデフォルトでは付きません。明示設定が必須

「JWTなら新しくてイケてる」の錯覚(業界事例)

2010年代後半のSPAブームで広まった誤解に、「SPAなんだからJWTをlocalStorageに入れるのが現代的」という刷り込みがあります。同一ドメインで動く普通のWebアプリでも、なぜかCookieセッションを避けてJWTに飛び付く事例が後を絶ちませんでした。

2017年頃に同じ思い込みでJWT + localStorage 構成を組み、後輩にXSS対策のレビューを受けて「これlocalStorageに置いていいんですか」と指摘されてようやく気付いた、という体験談はよく聞きます。

結果として、XSS一発で全ユーザーのJWTが流出し、しかもJWTの性質上即時失効できないため、攻撃者は有効期限まで好き放題という事例が繰り返し報告されています。Slackが2022年にGitHub経由で従業員トークンを盗まれた件も、仕組み自体はごく一般的なトークン認証で、コードは正しく動いていた構成でした。それでも保管場所と失効運用の甘さが突かれる、という典型例です。

JWTマイクロサービス横断・外部連携のように「ステートレスでないと成立しない場面」で光る技術で、同一ドメインの普通のWebアプリには過剰装備です。サーバセッション(Cookie)で済むなら、そちらの方が安全でシンプル。この判断を後回しにすると、あとで書き換える羽目になります。

「新しい方が正しい」は認証では通用しません。枯れた方式が選ばれ続けるのは理由があるのです。

決めるべきこと — あなたのプロジェクトでの答えは?

以下の項目について、あなたのプロジェクトの答えを1〜2文で言語化してみてください。曖昧なまま着手すると、必ず後から「なぜそう決めたんだっけ」が問われます。

  • セッション方式(サーバセッション / JWT / ハイブリッド)
  • Cookie属性(HttpOnly / Secure / SameSite)
  • Access Token有効期限 / Refresh Token Rotation
  • JWT署名アルゴリズム(RS256 / EdDSA、none禁止)
  • OAuthフロー(Authorization Code + PKCE ほぼ一択)
  • ログアウト時の処理(失効APIの実装)
  • Session IDエントロピー(128bit以上)

認証方式(MFAPasskeyIDaaS選定・パスワードポリシー)は別カテゴリ「セキュリティアーキテクチャ」の認証設計記事の決定項目です。

最終的な判断の仕方

セッション設計の核心は「ドメイン構造で方式を決める」ことです。同一ドメインのWebアプリはサーバセッション(Cookie)で十分安全かつシンプル、マイクロサービス横断・外部連携を伴うAPIはJWT + Refresh Token Rotation、外部サービス連携はOIDCに寄せる。この判断軸をブラさないことが設計の出発点です。

SPAだからJWTをlocalStorage」は2010年代の刷り込みで、XSS一撃で全ユーザー漏洩する古典的事故。httpOnly Cookie + サーバセッションか、JWTでもhttpOnly Cookie保管の方が安全です。

もう一つの軸は「標準プロトコルに寄せて、設定値を明示する」こと。OAuth 2.0 / OIDC / PKCEは標準化されており、AIもこれらは正確に書けます。独自トークン設計・独自フローは脆弱性の温床。

Cookie属性(HttpOnly / Secure / SameSite)とJWT署名アルゴリズム(RS256 / EdDSA、none禁止)、Refresh Token Rotationの有無はコードに明示し、デフォルト任せにしないこと。認証方式そのもの(MFAPasskeyIDaaS)は別カテゴリの担当で、本記事はセッションのに徹します。

選定の優先順位をまとめると次の通りです。

  1. ドメイン構造で方式を決める ― 同一ドメインはCookie、横断はJWT
  2. Cookie属性を明示する ― HttpOnly + Secure + SameSite=Lax は最低ライン
  3. JWTは短命Access + Refresh Token Rotation ― 失効できない問題の標準解
  4. OAuthはAuthorization Code + PKCE一択 ― Implicit / Password Grant は選ばない

「同一ドメインはCookie、横断はJWT迷ったらドメインで決めます。

まとめ

本記事は認証・セッション設計について、サーバセッション vs JWT・OAuth/OIDC・Cookie属性まで含めて解説しました。如何だったでしょうか。

同一ドメインはCookie、横断はJWT、外部連携はOIDC。Cookie属性は明示、JWTは短命+Refresh Token Rotation、OAuthはPKCE一択。これがソフトウェアアーキテクチャレベルでのセッション運用の現実解です。

これで「ソフトウェアアーキテクチャ」カテゴリ全8記事が完結しました。次回からは「アプリケーションアーキテクチャ」カテゴリに入り、クラス設計・ドメインロジック・命名規約・エラーハンドリングを解説していきます。

シリーズ目次に戻る → 『生成AI時代のアーキテクチャ超入門』の歩き方

それでは次の記事も閲覧いただけると幸いです。