第05章:ReactにApp Checkを入れる(v3版)⚛️🧿
この章は「React アプリが App Check トークンを付けて Firebase にアクセスできる状態」を作ります😊 ここができると、次の章以降で Firestore / Storage / Functions / Firebase AI Logic を“段階的に守る”準備が整います🛡️✨
この章でできるようになること 🎯
- React アプリ起動時に App Check を初期化できる🧿
- トークンが 自動更新されるようにできる♻️(これ重要!)(Firebase)
- Firebase Console の App Check メトリクスで「Verified が増えてる」ことを確認できる👀📈(Firebase)
ざっくり図解っぽく 🧠🖼️

App Check は「アプリが正規っぽいか」を証明する 通行証 です🎫
- ✅ 正規アプリ(React + App Check) → 通行証つきで Firebase にアクセス
- ❌ 不正スクリプト / API キー盗用 → 通行証なし(または偽造)で弾けるようになる
ポイント:Rules の代わりじゃないです🙅♂️ Rules は「誰が何できるか」、App Check は「正規アプリ経由か」を見るイメージ👍
まずは準備チェック ✅🧩
ここまでの章でやってる想定だけど、最低限これが揃ってればOKです👌
- Firebase Console で対象の Web アプリが登録済み
- App Check で reCAPTCHA v3 を選んで、site key と secret key を用意済み(secret は Console に登録)(Firebase)
⚠️ ローカル開発で localhost を reCAPTCHA の許可ドメインに入れたくなるけど、Web は Debug Provider を使うのが公式の筋です(この教材だと第13章でやるやつ)🧪🧿(Firebase)
手を動かす その1 依存関係を入れる 📦🖱️

React + Vite だとして(今いちばん自然な構成)、プロジェクト内で:
npm i firebase
(Node は LTS を使うのが安心です。たとえば v24 系が LTS として継続アップデートされています)(Node.js)
手を動かす その2 環境変数に site key を置く 🔑✨
Vite なら .env.local を作って:
VITE_RECAPTCHA_SITE_KEY=あなたの_site_key
site key は公開されても致命傷ではないけど、コードに直書きより管理しやすいのでここに置くのがラクです🙂
手を動かす その3 Firebase 初期化を 1か所に集約する 📦🧠

React で App Check を踏むときの事故で多いのがこれ👇
useEffectに書いて 二重初期化(React StrictMode や HMR のせい)😇- Firestore/Storage を先に触ってしまって App Check の初期化が間に合わない💥(Firebase)
isTokenAutoRefreshEnabledを入れ忘れて、気づいたらトークン期限切れ🍂(Firebase)
なので、この教材では **「firebase.ts 1枚に全部寄せる」**作戦でいきます👍
src/lib/firebase.ts を作る ✍️
// src/lib/firebase.ts
import { getApp, getApps, initializeApp } from "firebase/app";
import {
initializeAppCheck,
ReCaptchaV3Provider,
getToken,
type AppCheck,
} from "firebase/app-check";
// ✅ ここはあなたの Firebase プロジェクトの設定(Console からコピペ)
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY as string,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN as string,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID as string,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET as string,
appId: import.meta.env.VITE_FIREBASE_APP_ID as string,
};
// ✅ React + HMR 対策:Firebase App を多重生成しない
export const app = getApps().length ? getApp() : initializeApp(firebaseConfig);
// ✅ App Check は “1アプリにつき1回だけ” 初期化できるので、HMR 対策も入れる
const APP_CHECK_KEY = "__appCheckInstance__";
export const appCheck: AppCheck =
(globalThis as any)[APP_CHECK_KEY] ??
(() => {
const siteKey = import.meta.env.VITE_RECAPTCHA_SITE_KEY as string;
const instance = initializeAppCheck(app, {
provider: new ReCaptchaV3Provider(siteKey),
// ✅ Web は自動更新が「明示的に ON 推奨」
isTokenAutoRefreshEnabled: true,
});
(globalThis as any)[APP_CHECK_KEY] = instance;
return instance;
})();
// 🧪 動作確認用(本番ではログを減らすのがおすすめ)
export async function debugLogAppCheckToken() {
// getToken で “いまのトークン取れる?” を確認できる
const { token } = await getToken(appCheck);
console.log("App Check token (head):", token.slice(0, 20) + "...");
}
大事ポイント✅
initializeAppCheck()は 1つの Firebase App につき1回だけです(だから HMR 対策が効きます)(Firebase)ReCaptchaV3Providerは ブラウザ向けです(Node 環境では動きません)(Firebase)- そして何より、Firestore/Storage を触る前に App Check を初期化が基本です(Firebase)
手を動かす その4 React 側で “最初に” 読み込ませる 🚀⚛️

src/main.tsx(または src/main.jsx)のかなり上のほうで import します👇
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
// ✅ ここで firebase.ts を読み込ませる(= App Check が先に初期化される)
import { debugLogAppCheckToken } from "./lib/firebase";
debugLogAppCheckToken().catch(console.error);
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
これで「アプリ起動 → App Check 初期化 → トークン取得」までの流れができます🧿✨
動作確認 👀✅
1) ブラウザコンソールを見る 🔎
App Check token (head): xxxx...が出れば第一関門突破🎉 (出ないなら、site key / ドメイン / ブロッカー系を疑う)
2) Firebase Console の App Check メトリクスを見る 📈

App Check SDK を入れたら、強制を ON にする前にメトリクスで様子見するのが公式の流れです👀(Firebase)
メトリクスにはだいたいこんな分類が出ます👇
- Verified(通ってる)✅
- Outdated client(古いクライアント)🕰️
- Unknown origin(怪しい直叩き)👿
- Invalid(偽トークン等)🚫(Firebase)
よくある詰まりポイント集 😵💫🧯

1) initializeAppCheck を2回呼んで落ちる
- 原因:React StrictMode / HMR / 複数箇所 import
- 対策:この章の
globalThisガード方式でOK (App Check は 1回だけ、が仕様)(Firebase)
2) Firestore などを先に触ってる
- 原因:
firebase.tsを分散してしまった - 対策:App Check を先に初期化が基本です(Firebase)
3) トークンの自動更新を入れ忘れた
4) ローカルで reCAPTCHA ドメイン設定に悩む
- 公式は「
localhostを reCAPTCHA の許可ドメインに入れるより Debug Provider を使う」の流れです🧪🧿(Firebase)

AI 機能と App Check を最初から結びつける 🤖🧿💸

この教材の題材は「メモ+画像+AI整形」なので、AI が特に狙われやすいです(= お金が燃えやすい🔥)
Firebase AI Logic 側の現実ポイント 💰
- Firebase AI Logic は「プロジェクト全体の制限」だけでなく、“per user” 的に扱える quota 設計も案内されています
- しかもデフォルトが 100 RPM/ユーザーと高めなので、実運用では下げるのが推奨です🎛️(Firebase)
App Check と合わせるとこうなります👇
- App Check:正規アプリ以外を入れない🧿
- Rate limit:正規ユーザーでも連打で破産しない💸🚫(Firebase)
さらに、App Check は Firebase AI Logic も“強制対象”に含まれるので、段階導入ができます🛡️(Firebase)
Antigravity と Gemini CLI を使って実装を爆速チェック 🚀🤖
「初学者あるあるのミス(初期化順、重複、漏れ)」は AI がめっちゃ得意です🔎✨
しかも最近は Firebase 側が MCP サーバーを用意していて、Antigravity / Gemini CLI / Firebase Studio などから Firebase を“道具として”触れる流れが公式で整ってます🧰(Firebase) Gemini CLI には Firebase 公式拡張もあります🧩(Firebase)
使わせ方の例 📝(プロンプト案)
- 「React + Vite の構成で、App Check 初期化が複数回起きないかレビューして」👀
- 「Firestore/Storage/AI Logic を触ってる箇所を列挙して、App Check 初期化より後になってないか確認して」✅
- 「App Check が動かない時の原因候補(site key / ドメイン / ブロッカー)を優先度つきで出して」🧯
ミニ課題 🧩✨
課題:初期化を“1か所”に固定して、動作確認できる状態にする!
src/lib/firebase.tsに App Check 初期化をまとめる📦main.tsxで最初に import する🚀- Console にトークンっぽいログが出ることを確認する🔎
- Firebase Console の App Check メトリクスで Verified が出るのを確認する👀📈(Firebase)
チェック ✅🧾
-
initializeAppCheckが 1回だけ呼ばれてる(HMR でも落ちない)(Firebase) -
isTokenAutoRefreshEnabled: trueを入れた(Firebase) - App Check 初期化が “Firestore/Storage/AI” より先になってる(Firebase)
- メトリクスで Verified が確認できた(Firebase)
次章への伏線 🔁🏢
reCAPTCHA v3 はまず入り口として最高なんだけど、公式ドキュメントでも 新規は Enterprise 推奨の文脈が強いです📌(Firebase) Enterprise は **TTL が短め(デフォルト 1時間)**で、運用寄りのコントロールがしやすい方向です⏱️
次の第6章では、今日作った実装を “差し替え可能” にして、Enterprise へスムーズ移行できる設計にしていきます🔥