Firebase Hosting + Cloud Run で認証が動かない?Cookie名を __session にすべき理由
TL;DR
Firebase Hosting 経由で Cloud Run にアクセスする場合、セッション Cookie の名前は 必ず __session にする必要がある。それ以外の名前(session, auth, token など)は Firebase Hosting (CDN) によってストリップ(削除)され、バックエンドに届かない。
問題の症状
Next.js アプリを Firebase Hosting + Cloud Run で運用している際、以下のような不可解な現象に遭遇した:
- ✅ Cloud Run の URL(
https://<service>-<hash>.run.app)では正常にログインできる - ❌ Firebase Hosting の URL(
https://<project>.web.app)ではログインできない - Set-Cookie ヘッダーは正しく返されている
- ブラウザの Application タブでは Cookie が設定されている
- しかし Middleware では Cookie が
undefinedになる
根本原因:Firebase Hosting の Cookie 制限
Firebase Hosting は CDN として動作する
Firebase Hosting は静的コンテンツ配信のために CDN(コンテンツ配信ネットワーク)として動作する。CDN はキャッシュ効率を最大化するため、デフォルトで全ての Cookie をストリップ(削除)する。
ブラウザ → Firebase Hosting (CDN) → Cloud Run (バックエンド)
↑ここで Cookie がストリップされる__session だけが例外
Firebase Hosting は __session という名前の Cookie だけは例外的にバックエンドに転送するように設計されている。これは Firebase の公式仕様で、認証セッションを扱うための特別なルールである。
Firebase Hosting の Cookie ルール:
__sessionで始まる Cookie のみバックエンドに転送される- その他の Cookie は全てキャッシュ効率化のためストリップされる
- 最大 Cookie サイズは 4KB
参考: Firebase Hosting Documentation
なぜ Cloud Run URL では動いていたのか?
Cloud Run の URL に直接アクセスする場合は、Firebase Hosting (CDN) を経由しないため、Cookie がストリップされずにバックエンドに届く。
# Firebase Hosting 経由(CDN あり)
ブラウザ → Firebase Hosting → Cloud Run
↑Cookie がストリップされる
# Cloud Run 直接(CDN なし)
ブラウザ → Cloud Run
↑Cookie がそのまま届く| 環境 | Cookie 名 | 動作 | 理由 |
|---|---|---|---|
| Cloud Run URL 直接 | session | ✅ 動く | CDN を経由しない |
| Firebase Hosting URL | session | ❌ 動かない | CDN が Cookie をストリップ |
| Firebase Hosting URL | __session | ✅ 動く | CDN が __session だけは転送 |
解決方法
1. Cookie 名を __session に変更
変更前:
// ❌ Firebase Hosting でストリップされる
const COOKIE_NAME = 'session';
cookieStore.set('session', sessionCookie, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/',
});変更後:
// ✅ Firebase Hosting を通過する
const COOKIE_NAME = '__session';
cookieStore.set('__session', sessionCookie, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/',
});2. Middleware も更新
変更前:
// ❌ Firebase Hosting 経由では undefined になる
const sessionCookie = request.cookies.get('session');変更後:
// ✅ Firebase Hosting 経由でも取得できる
const sessionCookie = request.cookies.get('__session');3. テストも更新
テストで Cookie 名を直接参照している場合も更新が必要:
// 変更前
expect(mockCookieStore.set).toHaveBeenCalledWith('session', ...);
// 変更後
expect(mockCookieStore.set).toHaveBeenCalledWith('__session', ...);問題の診断方法
Firebase Hosting + Cloud Run 構成で認証問題が発生した場合、以下の手順で診断できる:
1. Set-Cookie ヘッダーの確認
ブラウザの DevTools → Network タブで、Set-Cookie ヘッダーが返されているか確認:
Set-Cookie: session=eyJhbGc...; Path=/; HttpOnly; Secure; SameSite=Lax✅ ヘッダーが返されている → Cookie 設定は成功
2. ブラウザの Cookie 確認
DevTools → Application タブ → Cookies で Cookie が保存されているか確認:
✅ Cookie が保存されている → ブラウザは Cookie を受け取っている
3. Middleware でのログ確認
Middleware に一時的なログを追加:
export async function middleware(request: NextRequest) {
const sessionCookie = request.cookies.get('session');
console.log('Cookie value:', sessionCookie?.value);
// ...
}❌ undefined が出力される → Firebase Hosting で Cookie がストリップされている
4. Cloud Run URL で直接テスト
Firebase Hosting を経由せず、Cloud Run の URL に直接アクセスしてテスト:
# Cloud Run URL を取得
gcloud run services describe <service-name> \
--region=<region> \
--format='value(status.url)'
# ブラウザで直接アクセス
https://<service>-<hash>.run.app✅ Cloud Run URL では動く → 問題は Firebase Hosting の Cookie 制限
まとめ
Firebase Hosting + Cloud Run 構成でセッション Cookie を使用する場合:
- Cookie 名は必ず
__sessionにする - Firebase Hosting は CDN として動作し、
__session以外の Cookie をストリップする - Cloud Run URL では動くのに Firebase Hosting URL では動かない場合、この問題を疑う
- Cookie サイズは 4KB 以内に収める
この制限は Firebase Hosting の仕様であり、回避することはできない。Firebase + Cloud Run でセッション認証を実装する場合は、最初から __session という名前を使用することを推奨する。
