第12章:Popup/Redirectの使い分け:詰まりどころ回避の知恵🧠
この章では、Googleログインを「Popup基本+Redirectも備える」にして、環境差で詰まらない構成にします😌🌈 (特に最近は、ブラウザのCookie/ストレージ制限が強くなってきてるので、ここを押さえると安心度が跳ねます🛡️)
0) この章のゴール🎯✨
- Popup と Redirect の違いが、ふんわりじゃなく判断できる🙂📌
- クリック1つで Popupを試してダメならRedirectへ…みたいな“強い導線”が作れる💪🚪
- Redirect時に必須の 戻り処理(getRedirectResult) を実装できる🔁✅
1) Popup と Redirect、なにが違うの?🤔🪟➡️

Popup(signInWithPopup)🪟
- 画面はそのまま、別ウィンドウでログイン → 戻ってくる✨
- WindowsのPCブラウザだと成功率が高い👍
- ただし、ポップアップブロックされることがある😇(企業PC設定とか、ブラウザ設定とか)
Redirect(signInWithRedirect)➡️
- 今のページからログインページへ移動 → 終わったら戻ってくる🔁
- モバイルや、ポップアップが厳しい環境で強い💪
- ただし注意:Firebase AuthのRedirectは内部で cross-origin iframe を使う都合があり、第三者ストレージ(3rd-party storage)をブロックするブラウザだとハマることがある⚠️ (Firebase)
- そして 2024-06-24以降、Chrome(M115+)でも“対策オプションの実装が必要” という扱いになっています(Firefox 109+ / Safari 16.1+ はそれ以前から要対策)📅⚠️ (Firebase)
2) 迷ったらこの方針でOK🙆♂️🧭

-
基本はPopup(PCならこれが一番ラク)🪟✨
-
Popupが無理なときだけRedirectへ(逃げ道として用意)➡️🛟
-
Redirectを“ちゃんと動かす”には、Firebase公式の Option 1〜5 のどれかを入れる必要がある🧰 (Firebase)
3) 手を動かす①:Popup→ダメならRedirect の関数を作る🛠️😎
ここがこの章のコアです🔥 UI側は「Googleでログイン」ボタンを押すだけでOKにします🎛️✨
3-1) Firebase初期化(例)🧱
// src/lib/firebase.ts
import { initializeApp } from "firebase/app";
import { getAuth, GoogleAuthProvider } from "firebase/auth";
const firebaseConfig = {
// Viteなら import.meta.env から読んでOK(ここは省略)
};
export const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const googleProvider = new GoogleAuthProvider();
3-2) “賢いGoogleログイン”関数を作る🪄

// src/features/auth/signInWithGoogleSmart.ts
import { FirebaseError } from "firebase/app";
import { signInWithPopup, signInWithRedirect } from "firebase/auth";
import { auth, googleProvider } from "@/lib/firebase";
type SmartSignInResult =
| { kind: "signed-in" }
| { kind: "redirecting" };
export async function signInWithGoogleSmart(): Promise<SmartSignInResult> {
try {
// ✅ 重要:signInWithPopup は「ボタンクリック」などユーザー操作の中で呼ぶ
await signInWithPopup(auth, googleProvider);
return { kind: "signed-in" };
} catch (err) {
// Popupがブロック/閉じられた系なら Redirectへ逃がす
if (isPopupTrouble(err)) {
await signInWithRedirect(auth, googleProvider);
// ここで画面遷移が起きる(戻り処理は後で getRedirectResult で拾う)
return { kind: "redirecting" };
}
throw err;
}
}
function isPopupTrouble(err: unknown): boolean {
if (!(err instanceof FirebaseError)) return false;
// よくある「Popupが使えない」系
return [
"auth/popup-blocked",
"auth/popup-closed-by-user",
"auth/cancelled-popup-request",
].includes(err.code);
}
3-3) ボタンにつなぐ(React)🖱️🌈
// src/components/GoogleSignInButton.tsx
import { useState } from "react";
import { signInWithGoogleSmart } from "@/features/auth/signInWithGoogleSmart";
export function GoogleSignInButton() {
const [busy, setBusy] = useState(false);
const [msg, setMsg] = useState<string | null>(null);
return (
<div>
<button
disabled={busy}
onClick={async () => {
setBusy(true);
setMsg(null);
try {
const r = await signInWithGoogleSmart();
if (r.kind === "redirecting") {
setMsg("ポップアップが難しそうだから、画面移動でログインするね🙂➡️");
}
} catch (e) {
setMsg("ログイン失敗…🥲(次の章でエラー翻訳を強化するよ)");
} finally {
setBusy(false);
}
}}
>
{busy ? "ログイン中…⏳" : "Googleでログイン🌈"}
</button>
{msg && <p style={{ marginTop: 8 }}>{msg}</p>}
</div>
);
}
4) 手を動かす②:Redirectの“戻り処理”を入れる🔁✅

Redirectは 戻ってきたあと に結果を拾わないと「なんか起きたけど分からん😇」になりがちです。
4-1) AuthProvider(または起動時のどこか)で getRedirectResult を呼ぶ🧠
ポイント:Firebase JS SDKは、Redirect利用時に onAuthStateChanged が getRedirectResult の解決を待つ挙動になっています(Observerが二重発火しにくい)🧯 (Firebase) それでも、エラー表示やログのために getRedirectResult を自分でも呼ぶのが実務ではラクです🙂
// src/features/auth/AuthProvider.tsx(例)
import { createContext, useEffect, useState } from "react";
import { FirebaseError } from "firebase/app";
import { auth } from "@/lib/firebase";
import { onAuthStateChanged, getRedirectResult, User } from "firebase/auth";
export const AuthContext = createContext<{
user: User | null;
loading: boolean;
authError: string | null;
}>({ user: null, loading: true, authError: null });
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [authError, setAuthError] = useState<string | null>(null);
useEffect(() => {
const unsub = onAuthStateChanged(auth, (u) => {
setUser(u);
setLoading(false);
});
// Redirect戻りの結果を拾う(無ければ null で終わる)
(async () => {
try {
await getRedirectResult(auth);
} catch (e) {
const msg =
e instanceof FirebaseError ? `${e.code}` : "redirect error";
setAuthError(`Redirectログインでエラー😵: ${msg}`);
}
})();
return () => unsub();
}, []);
return (
<AuthContext.Provider value={{ user, loading, authError }}>
{children}
</AuthContext.Provider>
);
}
5) Redirectが動かない系の“現代の罠”🕳️🧨

5-1) ブラウザのストレージ制限でRedirectが詰まることがある🍪🚫
Firebase公式が「redirect sign-in をスムーズにするため cross-origin iframe を使うが、第三者ストレージをブロックするブラウザでは動かない」と明記しています⚠️ (Firebase)
さらに重要: **2024-06-24以降、Chrome M115+ でも“Option実装が必須”**扱いです📅⚠️ (Firebase)
なので対策方針はこう👇
firebaseapp.comサブドメインの Hosting で運用してる → そのままでOK🆗 (Firebase)- Hostingのカスタムドメイン /
web.app→ Option 1 推奨🧩 (Firebase) - Firebase以外でホスト → Option 2〜5 を検討(難しめだけど、回避策はある)🧰 (Firebase)
この章の結論としては、まずPopupを基本にして、Redirectは“ちゃんと対策できる前提で”逃げ道にするのが事故りにくいです🙂🛡️
6) AIでUXを一段やさしくする🤖💬✨(Firebase AI Logic)
「ポップアップがブロックされた」「Redirectで詰まった」みたいな時に、ユーザーへ出す文言を やさしく説明できると神です😇✨
Firebase AI LogicのWeb例では、firebase/ai から getAI / getGenerativeModel を使う形が載っています📌 (Firebase)
あと、Gemini 2.0 Flash/Flash-Lite が 2026-03-31 に廃止予定なので、モデル名は新しめに寄せるのが安全です🧯 (Firebase)
6-1) “エラー説明をAIに作らせる”関数(例)📝

// src/features/ai/explainAuthTrouble.ts
import { getAI, getGenerativeModel, GoogleAIBackend } from "firebase/ai";
import { app } from "@/lib/firebase";
const ai = getAI(app, { backend: new GoogleAIBackend() });
// ✅ 例:軽量でUI向き(モデルは運用で差し替えしやすくするのが吉)
const model = getGenerativeModel(ai, { model: "gemini-2.5-flash-lite" });
export async function explainAuthTrouble(params: {
code?: string;
situation: string;
}): Promise<string> {
const prompt = [
"あなたはWebアプリのサポート係です。",
"次の状況を、初心者にも分かるように、短く、次の行動が分かる文章で説明して。",
"・難しい用語は避ける",
"・3行以内",
"",
`状況: ${params.situation}`,
params.code ? `エラーコード: ${params.code}` : "",
].join("\n");
const result = await model.generateContent(prompt);
return result.response.text() ?? "うまく説明できなかった…🥲";
}
※本番だと、モデル名をアプリに埋め打ちせず Remote Configで切り替えできるようにするのが推奨されています📌 (Firebase)
7) Antigravity / Gemini CLI で“詰まりどころ”を潰す🧑💻🧠🚀

-
Google Antigravityは「agentic IDE」として、調査→実装→テスト生成まで流れで支援する、という説明があります🤖🛠️ (Google Codelabs)
-
例プロンプト:
- 「Googleログインを Popup→失敗ならRedirect にして。戻り処理も入れて。エラーは人間向け文にして」🙂✨
-
-
Gemini CLIはターミナルで使えるエージェントで、MCPや組み込みツールで修正・調査もできる、という位置づけです🔎🧰 (Google for Developers)
-
例:
- 「redirect が発生してるのに getRedirectResult が呼ばれてない箇所ある?」
- 「auth/popup-blocked を握りつぶしてない?」
-
8) ミニ課題🎒✅
- ログインボタンを押す
- Popupが成功したら「ログインできた🎉」
- Popupが失敗したら Redirect に切り替わる(文言も出す)➡️
- 戻ってきたら getRedirectResult を通して、エラー時は画面に表示😵💫
9) チェック✅🧾
-
signInWithPopupは クリックイベント内で呼んでる?(これ大事🧠) - Popup失敗時に Redirectへ逃げる導線がある?🛟
-
getRedirectResultを起動時に呼んで、戻り結果/エラーを拾えてる?🔁 - Redirectを本番で使うなら、Option対策が必要だと理解できた?(Chrome M115+ は 2024-06-24 以降必須)📅⚠️ (Firebase)
- AIで「次に何をすればいいか」を短く案内できる?🤖💬 (Firebase)
次の章(Cookie制限時代のベストプラクティス)に行くと、Redirect周りの“現代の地雷”をさらに安全に踏み抜けるようになります🛡️🔥