2025/08/11

ユースケースで選ぶSPAの認証——Laravel 12の Session / Sanctum とOIDC

まとめ

  • 同一ドメインSPA × ブラウザだけLaravel Session(stateful)単独でも実装可能。ただし公式はSPAにはSanctum推奨

  • routes/api.php を保ったままSPAを stateful にしたい or 同一トップレベルドメイン内の別サブドメインSPASanctum(SPAモード)

  • 別ドメインのSPA(例:spa.example.comapi.other.comSanctum(SPA)不可

    • セッションで運用したいならBFF同一サイトに集約
    • もしくはstatelessSanctum Token / OAuth/OIDC)へ
  • モバイル / 外部クライアントstateless が必要。Sanctum(Token)OAuth/OIDC

  • 外部OIDCを使うBFF(Code+PKCE→サーバ交換→アプリのセッション)が基本。Sanctumは必須ではない

はじめに

今回はLaravelでSPAのWebアプリケーションを作成する際に利用できる認証機能を、ユースケース別の選び方という観点で整理します。Laravelには複数の手段があり、設計上の注意点も多いため混乱しがちです。そこで、要件から逆引きできる判断軸を提示します。

なぜここで迷うのか

  • Sanctumは2つの機能(APIトークン発行とSPA認証)を提供。SPA認証はトークンを使わずセッションを使う。
  • SPA認証は同一トップレベルドメイン前提(サブドメインは可)。
  • auth:sanctum自社SPAのCookieセッションサードパーティのAPIトークンを両方受けられる設計。
  • LaravelはXSRF-TOKEN Cookieを発行し、同一オリジンではAxios等がX-XSRF-TOKENを自動付与。
  • Laravelのブラウザ向け既定はセッションガード。一方でSPAやハイブリッドにはSanctum推奨

用語の確認

stateful(セッション型)

  • 概要 ブラウザにCookie(セッションID)、サーバにセッション状態を持たせる認証。Laravelでは session ガードで実現。
  • どう成り立つか ログイン成功 → セッションに保存 → 以後はCookieのセッションIDでユーザー復元。CSRFはXSRF-TOKEN Cookie → X-XSRF-TOKENで防御(SPAではAxios等の自動付与を活用)。
  • 利点 即時失効や権限変更の即反映が容易。長寿命トークンを置かないためXSS耐性が比較的高い。
  • 注意点 スケール時は共有セッションストア(Redis等)。Cookie属性(SameSite/Secure/Domain)やCORS設計が必要。

stateless(トークン型)

  • 位置づけ サーバ側にブラウザ専用状態を持たず、毎リクエストでBearerトークンを検証。
  • どう成り立つか クライアントが Authorization: Bearer <token> を毎回送信。サーバは署名/JWKs/DB照合で都度認証
  • 利点 多クライアント(モバイル/外部)向き。マルチリージョン/エッジに載せやすい。
  • 注意点 失効・ローテーション・保管の運用コストが高め。長寿命トークンの漏えい対策が要。

Sanctum認証

Sanctum(SPAモード)

  • 概要 自社SPAからのAPIstateful(Cookie+セッション)として扱う。auth:sanctum はまず認証Cookieを確認し、無ければAuthorizationヘッダのAPIトークンを確認。

  • 実現方法(概略)

    1. config/sanctum.phpstateful ドメインを設定
    2. bootstrap/app.phpstatefulApi() を有効化
    3. 初回に /sanctum/csrf-cookie でXSRF初期化
    4. 以降はセッションCookie+CSRFで認証(Axiosは withCredentials / withXSRFToken を推奨)
  • 要件・注意

    • 同一トップレベルドメイン必須サブドメインは可だが、異なるレジストラブルドメインは不可
    • リクエストには Accept: application/jsonOrigin または Referer を付与。
    • クロスサブドメインでCookieを共有する場合は SESSION_DOMAIN やCookie属性・CORS設定を適切に。

Sanctum(Tokenモード)

  • 概要 GitHubのPATのようなAPIトークンを発行し、BearerでAPI認証する軽量トークン方式(非JWTでも可)。

  • 実現方法(概略)

    1. ユーザーに HasApiTokens を付与
    2. createToken() で発行(DBにはSHA-256でハッシュ保存平文は発行時のみ表示
    3. ルートを auth:sanctum で保護
  • 使いどころ モバイル/外部クライアントや社内APIのシンプルなトークン配布に適合。自社SPAの認証には使わずSPAはSanctumのSPA機能を使う。


分岐フロー

Q1: 自社ブラウザSPAだけ?
 ├─ Yes → Q2
 └─ No(外部/モバイルあり) → stateless要件 → Sanctum Token or OAuth/OIDC

Q2: 同一トップレベルドメイン内で出せる?
 ├─ Yes(同一サイト or サブドメイン)→ Laravel Session(最小) or Sanctum(SPA)※api.php維持なら推奨
 └─ No(別レジストラブルドメイン)→ Sanctum(SPA)不可
        → BFFで同一サイト化(セッション運用) or stateless(Sanctum Token / OAuth/OIDC)

補足: OIDC採用? → BFFなら最終的にアプリのセッションで運用(Sanctum必須ではない)

迷いがちなポイント

  • 「JS(SPA)ならSanctum必須?」必須ではない同一ドメインならセッションのみでも可能。ただし公式はSPAにはSanctum推奨
  • 「自社SPA向けAPI」とは?」自分たちが配信するブラウザSPAからの呼び出し(第三者やモバイルは含まない)。
  • CSRFはどう効く? → LaravelがXSRF-TOKEN Cookieを付与。同一オリジンではAxios等がX-XSRF-TOKENを自動付与。クロスサブドメインでは withCredentials 等の設定+Sanctum側のstateful設定が必要。
  • 即時失効を重視するなら?statefulが楽。auth:sanctum 運用でもCookie側で即時無効化しやすい。

まとめ

  • 誰が(自社/外部/モバイル) × どこから(同一サイト/サブドメイン/別ドメイン) × **運用要件(即時失効/拡張性)**で選ぶ。

  • 迷ったら:

    • 同一サイトSPA → まずはセッションapi維持や拡張性重視ならSanctum(SPA)
    • 別レジストラブルドメインBFFで同一サイト化 or stateless(Sanctum Token / OAuth/OIDC)。
    • 多クライアントstateless前提(Sanctum Token / OAuth/OIDC)。