まとめ
-
同一ドメインSPA × ブラウザだけ → Laravel Session(stateful)単独でも実装可能。ただし公式はSPAにはSanctum推奨。
-
routes/api.php
を保ったままSPAを stateful にしたい or 同一トップレベルドメイン内の別サブドメインSPA → Sanctum(SPAモード)。 -
別ドメインのSPA(例:
spa.example.com
とapi.other.com
) → Sanctum(SPA)不可。- セッションで運用したいならBFFで同一サイトに集約
- もしくはstateless(Sanctum 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からのAPIをstateful(Cookie+セッション)として扱う。
auth:sanctum
はまず認証Cookieを確認し、無ければAuthorizationヘッダのAPIトークンを確認。 -
実現方法(概略)
config/sanctum.php
でstateful
ドメインを設定bootstrap/app.php
でstatefulApi()
を有効化- 初回に
/sanctum/csrf-cookie
でXSRF初期化 - 以降はセッションCookie+CSRFで認証(Axiosは
withCredentials
/withXSRFToken
を推奨)
-
要件・注意
- 同一トップレベルドメイン必須。サブドメインは可だが、異なるレジストラブルドメインは不可。
- リクエストには
Accept: application/json
とOrigin
またはReferer
を付与。 - クロスサブドメインでCookieを共有する場合は
SESSION_DOMAIN
やCookie属性・CORS設定を適切に。
Sanctum(Tokenモード)
-
概要 GitHubのPATのようなAPIトークンを発行し、BearerでAPI認証する軽量トークン方式(非JWTでも可)。
-
実現方法(概略)
- ユーザーに
HasApiTokens
を付与 createToken()
で発行(DBにはSHA-256でハッシュ保存/平文は発行時のみ表示)- ルートを
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)。
- 同一サイトSPA → まずはセッション、