定義
ログインが必要な API を呼ぶ 前に、「今は未ログイン」ではなく「セッション判定が終わったか」を先に確認する技法である。
認証解決(auth resolution) とは、アプリが Cookie・トークンでセッションを復元するか、「セッションなし」を確定した状態である。その前は user が一時的に null になりうる。ゲーティング(gating) とは、React Query などの enabled で fetch のオン/オフを制御することである。典型的な式は enabled: authResolved && isAuthenticated である。
なぜ必要か
セッション復元は非同期である。ローディング中に !user だけを見て保護リソースを叩くと 401 Unauthorized が発生し、グローバルハンドラが /login へ送って 公開ホーム・SEO ページまで壊れる。テスト用 MSW(モックネットワーク)は 401 を出さなかったりタイミングを隠したりするため、実ブラウザ(Cookie なしコンテキスト) でのみ再現されるバグになる。
動作原理
- auth レイヤーが
status: 'loading' | 'authenticated' | 'anonymous'(またはresolved: boolean)を公開する。 - 保護クエリ:
enabled: status === 'authenticated'(またはresolved && !!user)。 - 公開/匿名ページ: 保護クエリは
enabled: false、モック・静的データのみ使用。 isAnonymousを!userだけで定義しない — loading 中に true になると 誤った匿名 UI・誤った fetch が起きる。- グローバル 401→ログインリダイレクトは保護ルートにのみ適用するか、公開パスを例外処理する。
実務での適用
- 公開ランディング/ホーム: メタ・JSON-LD・FAQ はサーバー/静的、ワークスペース API はオフ。
- ヘッダー・タブクリック: 匿名ならナビゲーションではなくログインダイアログ。
- E2E: MSW だけで「匿名 OK」と断定せず、Cookie 隔離の実ブラウザでネットワーク 401 の有無を確認する。
- ローディング UI:
resolved === falseのときはスピナー/スケルトン、匿名確定後にのみロックパネル。
トレードオフ
| 選択 | 利点 | コスト |
|---|---|---|
| 厳格ゲート | 公開ページの安定 | 解決前のデータ空白(スケルトンが必要) |
!user だけで fetch | 実装が単純 | ローディング中の 401・リダイレクト |
| グローバル 401→login | セキュリティ UX が単純 | SEO・匿名プレビューと衝突 |
使うべきでない場合
- もともと公開 API だけを使うページに過度な auth ゲートを付けて不要な遅延を作る場合。
- サーバーコンポーネントですでにセッションを確定しているのに、クライアントで重複してブロックし原因を隠す場合(境界を文書化すること)。
よくある失敗
isAnonymous = !user→ loading 中も匿名扱いになる。- E2E だけ緑、本番でのみログインへ弾かれる。
- 401 ハンドラが すべての fetch 失敗で
/login— 公開リソースの 404/ネットワークエラーまでログインへ送る。
関連概念
- race-safe-async-ui-requests — リクエストキャンセル・最新レスポンスのみ反映
- structured-data-visible-content-parity — 公開ホームが開いたときに埋めるコンテンツのルール