まとめ
-
同一ドメイン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 → まずはセッション、
