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

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

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

本記事について

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

本記事の問いは「ログイン後のセッションをどう持つか」です。サーバセッション vs JWTOAuth 2.0/OIDC・Cookie属性の安全設定まで扱い、認証強度(MFA / Passkey / IDaaS)とブラウザ防御(XSS / CSP)はそれぞれセキュリティ章・フロントエンド章に委ねます。

本記事のテーマについてさらに詳しく知りたい方は『セキュア・バイ・デザイン』も参考にしてみてください。

この記事の結論

  • 同一ドメインはCookieセッション、ドメイン横断はJWT
  • JWTは短命(15分)+Refresh Token Rotation。localStorageには置かない
  • OAuthはAuthorization Code+PKCE一択、外部連携はOIDC
  • Cookie属性(HttpOnly / Secure / SameSite)は必ず明示する

この記事を読む前に

本記事はプログラムやAPIといった開発寄りの話が中心です。IT用語にあまり馴染みがない方は、基礎編の「プログラムとAPIの基本」を先に読んでおくと格段に分かりやすくなると思います。また、読んでいて分からない用語が出てきたときは用語集で調べながら読み進められます。

そもそも認証・セッション設計とは何か

認証・セッション設計とは、ざっくり言えば「ログイン後のユーザーをどうやって覚えておくかの仕組みを決めること」です。

遊園地の入場を想像してください。入口でチケットを見せて本人確認する(認証)のは一度きりで、園内ではリストバンド(セッション)を見せるだけでアトラクションに乗れます。リストバンドをサーバー側で管理するか、来場者自身に持たせるか──この選択がサーバセッション方式とJWT方式の違いです。

なお混同されがちですが、認証(Authentication)は「あなたは誰ですか」を確認する処理、認可(Authorization)は「あなたは何ができますか」を決める処理です。「ログインできたから管理者操作もできる」は典型的な混同で、この2つは別物として設計します。

なぜ認証・セッション設計が重要なのか

もしセッション管理の選択を誤ると、致命的なセキュリティホールになります。JWTの保管場所を間違えればXSSで盗まれ、Cookieの属性設定を忘れればCSRFで操作される──セッション周りの設計ミスは直接的な不正アクセスにつながります。

さらにマイクロサービス化すると、モノリスでは1箇所で済んだセッション管理が全サービスにまたがります。最初に方式を統一しないと、サービスごとにバラバラな認証実装が乱立します。AIエージェントがAPIを叩く時代では、人間のブラウザセッションとは別の認証フローも必要になり、両方を見据えた設計が求められます。

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

認証後、再ログインなしでAPIを使い続けられるようにする仕組みがセッション管理です。方式は大きく2つに分かれます。

サーバセッション ― 同一ドメインの既定解

ログイン成功時にサーバーがランダムなセッションIDを発行してCookieに保存させ、以降のリクエストではRedis等のストアを参照してユーザー情報を取り出す方式です。即時失効が可能(ストアから消せば無効)、漏洩時の被害を局所化しやすい、ライブラリが成熟しているという強みがあり、同一ドメインの一般的なWebアプリ・SPAならサーバセッションで十分かつ安全です。弱点はセッションストアの運用が必要なことと、スケールアウト時に全台でストアを共有する必要があることです。

JWT ― ドメイン横断のための道具

JWTは、ユーザー情報そのものを署名付きトークン(Header.Payload.Signature)に詰めてクライアントに渡す方式です。サーバーは署名を検証するだけで認証でき、状態を持たない(ステートレス)ため、マイクロサービスが複数立ち並ぶ構成で各サービスが独立して認証処理できます。

代わりに罠も多い方式です。即時失効が困難(トークンは期限まで有効)なため、短命のAccess Token+httpOnly Cookieに入れたRefresh Tokenの組み合わせが定石です。ペイロードはBase64で誰でもデコードできるので機密情報を入れてはならず、localStorageに保存するとXSS一発で盗まれるためhttpOnly Cookieに保管します。JWT=localStorage」という組み合わせは、2024年以降のセキュリティガイドラインでは事実上の禁則です。

OAuth 2.0 / OIDC

OAuth 2.0 + PKCE 認可コードフロー

OAuth 2.0「認可の委譲」のプロトコルで、「このアプリにGoogle Driveの読み取り権限を渡す」のように第三者アプリへAPIアクセス権限を渡す仕組みです。OpenID ConnectOIDC)はOAuthを土台に認証を標準化した拡張で、「Googleでログイン」はOIDCで実現されています。標準化されたプロトコルなので、自前で実装せずAuth0 / Firebase Auth / Cognito / Okta等に委譲するのが現代の主流です。

フローは用途別に分かれますが、新規実装ではAuthorization Code+PKCEがほぼ一択です。認可コードをブラウザ経由で受け取りサーバー側でトークンと交換する2段構えで、PKCEにより途中で認可コードを横取りされても攻撃者がトークンに交換できません。

フロー用途
Authorization Code+PKCESPA・モバイル・Webアプリ(標準)
Client Credentialsサーバ間通信(ユーザーが介在しない)
Device CodeTV・CLIなど入力困難な端末
Implicit Flow / Password Grant非推奨(古い情報源に注意)

どう選べばいいのか ― ドメイン構造で決める

判断軸はシンプルです。従来型Webアプリ・SPA+API(同一ドメイン)ならサーバセッション(Cookie)が既定です。「SPAだからJWT」は誤解で、httpOnly Cookieで十分安全です。マイクロサービス・横断認証ならJWT+Refresh Token。外部ログイン連携(Google・GitHub等)はOIDCでAuth0 / Firebase Authに委譲。社内システム(SSO必要)はOIDC+SSO基盤(Okta / Entra ID)で人事異動の権限変更も一元管理します。

どの方式でも、Cookie属性の設定が安全性を大きく左右します。「HttpOnly(JSから読めない)+Secure(HTTPSのみ)+SameSite=Lax(CSRF防止)」はWebアプリの最低ラインです。

// 推奨: 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);

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

※ 2026年4月時点の業界相場値です。

「なんとなく」で決めると必ず脆弱性を生むため、具体的な数値基準を最初に決めます。

設定項目推奨値
Access Token(JWT)有効期限15分
Refresh Token(httpOnly Cookie)有効期限14〜30日+Rotation有効化
Session IDエントロピー128bit以上
JWT署名アルゴリズムRS256 / EdDSAnone は絶対禁止)
CSRF対策SameSite=Lax+CSRFトークンの二重防御

JWTnone アルゴリズムは署名検証なしで偽造可能になるため絶対に許可しません(2018年に複数ライブラリで脆弱性が多発)。Refresh Tokenは使用ごとに新しい値を発行(Rotation)し、古い値が再利用されたらセッション全失効という運用が現代の定石です。

3つのシナリオで考える

個人開発・スタートアップの場合

ClerkやAuth.js、Supabase Authへの委譲一択だと思います。セッション管理・トークンローテーション・OAuth連携を自前で書くのは、個人開発で最も時間を溶かす罠だからです。方式としてはhttpOnly Cookieのサーバセッションが既定で、SPAだからJWTという誤解に乗らないことが重要になります。

個人・スタートアップ ― 1か月で出せる構成が正解 ― 生成AI時代のアーキテクチャ超入門senkohome.com/arch-intro-case-startup/

中小SaaSの場合

Auth0やCognitoを使いつつ、同一ドメインならサーバセッション、サービス分割時はJWTとRefresh Token Rotationの組み合わせ、という使い分けになります。Access Tokenは15分、Refresh Tokenは14〜30日にRotation有効化という数値Gateを守り、B2B向けにはSAMLOIDC対応をIdP選定時に確認しておいてください。

中小SaaS ― マネージドに寄せて少人数で回す ― 生成AI時代のアーキテクチャ超入門senkohome.com/arch-intro-case-saas/

大企業の場合

OIDCSSO基盤(OktaやEntra ID)へ統合するのが前提となります。こうしておけば人事異動の権限変更を一元管理できますし、退職者アカウントの放置も構造的に防げるのです。逆に、社内システムごとに独立した認証DBを作るのはセキュリティ事故の温床ですので、絶対に避けるべきです。

大企業基幹系 ― 新しい技術より組織で成立する設計 ― 生成AI時代のアーキテクチャ超入門senkohome.com/arch-intro-case-enterprise/

AI判断軸 ― AIが書ける領域と落とす箇所

AI駆動開発が前提になると、セッション実装は「AIが正しく書ける領域」と「明示しないと省略される領域」がきっぱり分かれます。

AIが正しく書ける実装と、落とす箇所

AIはOAuth 2.0 Authorization Code+PKCEのフロー全体を正確に書けます。RFC 7636に忠実なcode_verifierの生成からtokenエンドポイントへのPOSTまで、ほぼ間違えません。問題は運用面の設定で、SameSite=Lax の未設定、Refresh Token Rotationの省略、ログアウト時にサーバ側のRefresh Tokenを失効させるAPIの欠落、HttpOnly の付け忘れがよく起きます。これらはAIが「書けない」のではなく、明示的に指示しないと省略する箇所です。機能テストでは見つからない(認証フローが動いていてもセキュリティ設定が甘い状態はパスしてしまう)ため、レビューチェックリストと静的解析で拾う前提の設計が必要です。

IDaaS SDK利用時のAI活用パターン

Auth.js(旧NextAuth)・Clerk・Firebase Authのような認証SDKを使う場合、ドキュメントが充実して学習データも豊富なため、AIの生成精度は非常に高くなります。自前のセッション管理を書かせるより、SDKのセットアップとミドルウェア設定を書かせる方が安全かつ正確です。

Auth.js(NextAuth)によるSDKベース認証構成 認証は自前実装せずSDKに委譲。AIの生成精度も高い定番構成 Next.js アプリケーション Auth.js 設定 providers: [Google, GitHub] callbacks: { jwt, session } secret: env.AUTH_SECRET Middleware 保護パスの指定 /dashboard /api/* 未認証→リダイレクト HttpOnly Cookie(Secure / SameSite=Lax)でセッション管理 外部認証プロバイダ Google OIDC GitHub OAuth Auth0 / Okta / Clerk 自前で認証ロジックを書かない SDKが安全な実装を担保 OIDC AI生成コードのレビュー4点: localStorage禁止 / Cookie属性4点 / 失効API / PKCE対応

やってはいけないこと

セッション実装で事故る典型パターンは、どれもアカウント乗っ取り・成りすましに直結します。特に危険な6つに絞ります。

禁じ手なぜダメか → どうするか
JWTをlocalStorageに保存XSSで簡単に盗まれる → httpOnly Cookieに保管する
Cookie属性を設定しないXSS・盗聴・CSRFの全てが成立する → HttpOnly+Secure+SameSiteを明示する
「SPAだからJWT」でCookieセッションを避ける同一ドメインならCookieの方が安全かつシンプル → ドメイン構造で選ぶ
JWTの失効設計なし漏洩時に無効化できない → 短命Access+Refresh Token Rotationにする
Implicit Flow / Password Grantを新規採用2020年以降は非推奨 → Authorization Code+PKCEにする
ログアウト時にCookie削除のみサーバ側のRefresh Tokenが生き残る → 失効APIを実装する

認証方式そのもの(パスワード保存・MFAPasskey)の鬼門は別カテゴリ「セキュリティアーキテクチャ」を参照してください。

筆者メモ ― 「JWTなら新しくてイケてる」の錯覚

2010年代後半のSPAブームで広まった誤解に、「SPAなんだからJWTをlocalStorageに入れるのが現代的」という刷り込みがあります。同一ドメインで動く普通のWebアプリでも、なぜかCookieセッションを避けてJWTに飛び付く事例が後を絶ちませんでした。結果として、XSS一発で全ユーザーのJWTが流出し、しかもJWTの性質上即時失効できないため、攻撃者は有効期限まで好き放題という事例が繰り返し報告されています。

JWTマイクロサービス横断・外部連携のように「ステートレスでないと成立しない場面」で光る技術で、同一ドメインの普通のWebアプリには過剰装備です。「新しい方が正しい」は認証では通用しません。枯れた方式が選ばれ続けるのは理由があるのです。

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

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

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

言語化した答えはADRとして残します。書き方の具体例は以下の記事で解説しています。

ドキュメンテーション ― README+ADR+OpenAPIをGitに寄せる ― 生成AI時代のアーキテクチャ超入門senkohome.com/arch-intro-devops-docs/

この記事に関連する記事

まとめ

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

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

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

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

本記事で扱った内容の詳細は OAuth 2.0 も合わせて参考にしてください。

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