第18章:自前バックエンドを守る(X-Firebase-AppCheck を検証)🧱🛡️
この章はひとことで言うと 「Firebaseの外にある“自分のAPI”も、App Checkで“正規アプリだけ”にする」 回です🙂✨ (たとえば:Cloud Run のAPI、コンテナで動くExpress、社内API、AI処理専用APIなど)
まず結論:守りの“最小セット”はこれ🧿✅
自前APIを守るとき、最低限の型はこう👇
- フロント(React):App Check トークンを取って、HTTPヘッダ
X-Firebase-AppCheckに載せて送る📮 - バック(自前API):ヘッダのトークンを Admin SDKで検証(成功したらOK、失敗は401)🚫 → これで「あなたのFirebaseプロジェクトに属する“正規アプリ”から来た」ことが確認できます✅ (Firebase)
さらに強くするなら(おすすめ!)👇
- ユーザー本人確認もセット:
Authorization: Bearer <Firebase Auth ID token>も一緒に送り、バックでverifyIdToken()する🙋♂️🔐 (Firebase) - 超重要APIはリプレイ対策:limited-use token + サーバ側で “consume” して使い回しを潰す♻️🚫 (Firebase)
しくみ(超ざっくり図)🗺️

- React(ブラウザ)
→ App Check SDKでトークン取得
→
X-Firebase-AppCheck: <token>を付けてfetch() - 自前API(Express / Cloud Run 等) → ヘッダを見てトークン検証 → OKなら処理(Firestore読書き、画像処理、AI呼び出し等) → NGなら 401
読むパート(今日の公式仕様の“肝”だけ)📖✨
1) フロント:ヘッダに載せる(URLに埋めない!)🚫🔗

Webアプリでは App Check トークンを取って、X-Firebase-AppCheck ヘッダで送ります📮
トークンは URL(クエリ)に入れない のが推奨です(ログや参照元で漏れやすい…😇)。(Firebase)
さらに、リプレイ対策をしたい場合は getLimitedUseToken() を使う方法が案内されています。(Firebase)
2) バック:Admin SDKで検証して、ダメなら落とす🧱🔍
自前API側はやることが明確👇
- トークンが付いてるかチェック
- Admin SDKで検証(成功なら続行、失敗なら401)(Firebase)
手を動かす(React側):トークンを付けて自前APIを叩く⚛️📮

App Check が初期化済みの前提で、API呼び出し関数を1つ作ります🙂 (※ここでやってるのは「ヘッダに載せる」だけ。シンプル!)
import { getAppCheck, getToken /*, getLimitedUseToken */ } from "firebase/app-check";
/**
* 自前APIを叩く共通関数(App Check トークンを自動付与)
*/
export async function callMyApi(path: string, body: unknown) {
const appCheck = getAppCheck();
// 通常トークン(まずはこれでOK)
const { token } = await getToken(appCheck, /* forceRefresh */ false);
// リプレイ対策を強くしたいAPIだけ、こっちを検討👇
// const { token } = await getLimitedUseToken(appCheck);
const res = await fetch(`/api${path}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Firebase-AppCheck": token,
},
body: JSON.stringify(body),
});
if (!res.ok) {
// 401 なら「App Check通ってない」可能性が高い
const text = await res.text().catch(() => "");
throw new Error(`API error: ${res.status} ${text}`);
}
return res.json();
}
ポイントは2つだけ!✨
手を動かす(Node/Express側):ミドルウェアで検証する🧰🛡️

公式ドキュメントの Express ミドルウェア例がそのまま使えます👍 「まずは通す/落とす」だけ作って、あとで本処理を足すのが安全🙂
import express from "express";
import { initializeApp } from "firebase-admin/app";
import { getAppCheck } from "firebase-admin/app-check";
const app = express();
app.use(express.json());
// Cloud Run / Functions / サーバなどで、権限のあるサービスアカウントで動く想定
initializeApp();
/**
* App Check 検証ミドルウェア
*/
async function requireAppCheck(req: express.Request, res: express.Response, next: express.NextFunction) {
const appCheckToken = req.header("X-Firebase-AppCheck");
if (!appCheckToken) {
return res.status(401).send("Unauthorized");
}
try {
const claims = await getAppCheck().verifyToken(appCheckToken);
// 必要なら claims を req に載せてもOK(例: appId をログ用に)
(req as any).appCheckClaims = claims;
return next();
} catch {
return res.status(401).send("Unauthorized");
}
}
app.post("/api/ai/formatMemo", requireAppCheck, async (req, res) => {
// ここに「AI整形処理」など好きなロジックを書く🤖✨
res.json({ ok: true });
});
app.listen(8080, () => console.log("server on :8080"));
この流れ(ヘッダ必須→verify→失敗は拒否)は公式が明示しています。(Firebase)
さらに強く:Authも一緒に検証して「誰が叩いたか」まで確定🙋♂️🔐

App Check は「正規アプリか?」で、Auth は「ユーザー本人か?」です。 自前APIで“課金に直結するAI”をやるなら 両方やる のが鉄板🙂
フロント側:Authorization も付ける(例)
Authorization: Bearer <ID token>
バック側:Firebase Admin SDK で verifyIdToken() する流れが公式にあります。(Firebase)
(ここまでできると、ユーザー別レート制限とか、管理者のみ許可とかが作りやすいです💪✨)
超重要APIだけ:リプレイ対策(使い回し攻撃)を潰す♻️🚫

「AI実行」「購入」「招待コード発行」みたいな 一発が重いAPI は、次の合わせ技が強いです👇
- フロント:
getLimitedUseToken()を使う (Firebase) - バック:
verifyToken(token, { consume: true })で “消費” する (Firebase)
Admin SDK側は “consume” を指定できて、結果に すでに消費済みか の情報も返ります。(Firebase)
+発展:.NET(公式Admin SDKが無い言語)で検証したい場合🧩🟣

自前バックエンドが “別言語” のときは、公式が「JWTライブラリで検証する手順」を出しています👇
- 公開鍵(JWKS)を
https://firebaseappcheck.googleapis.com/v1/jwksから取得 - 署名検証
- ヘッダ
algが RS256、typが JWT - issuer(発行者)が自分のプロジェクト配下
- 期限切れじゃない
- audience が自分のプロジェクト
- (任意)subject がアプリの App ID と一致 (Firebase)
しかも鍵はローテするので ハードコードしない、ただし 最大6時間くらいはキャッシュしてOK とまで書いてあります。(Firebase)
バージョン目安:.NET は .NET 10(LTS) が現行の安定ど真ん中です。(Microsoft)
.NETで作るならチェックリスト(コピペ用)✅
-
X-Firebase-AppCheckヘッダがある - JWKS取得(キャッシュあり)
- RS256 / typ=JWT
- 署名OK
- issuer OK(自分の project number 配下)(Firebase)
- audience OK(自分の project number)(Firebase)
- exp(期限)OK
- (任意)subject == App ID
AI活用:Antigravity / Gemini CLI で“守り実装”を爆速にする🚀🤖
ここ、AIがめちゃ効きます😆🔥 特にこの章は「いつものWeb API」なので、雛形生成が速い!
Antigravity(Mission Control)でやらせると強い🛰️
Antigravityは「エージェントが計画して、コード書いて、必要ならWebも見て進める」思想が明記されています。(Google Codelabs) ミッション例👇
- 「
/api/ai/formatMemoを作る。App Check検証必須。失敗は401。ログはトークンを出さない」 - 「重要APIは limited-use token + consume 対応」
Gemini CLI(ターミナルで)でやらせると楽🔧
Gemini CLI は ターミナルで使えるオープンソースAIエージェントとして案内されています。(Google Cloud) お願いのコツ👇
- 「このファイルに
requireAppCheckミドルウェア追加して」 - 「
X-Firebase-AppCheckがURLに入ってたら指摘して」 - 「401のとき、UI側でどう見せるべき?」(第15章につながる🙂)
(Firebase Studioを使うなら .idx/dev.nix でツール環境を揃えられるので、チームでも再現しやすいです🧰)(Firebase)
ミニ課題🎯(10〜20分)
- Reactから自前APIを叩くボタンを作る🔘
X-Firebase-AppCheckを付けたときだけ成功するのを確認👀- 401のときに「再読み込み」「時間を置く」「問い合わせ導線」表示を入れる🙂🧯
- (余裕あれば)重要APIだけ
getLimitedUseToken()+consume: trueにして、再送で弾けるか試す♻️🚫 (Firebase)
チェック✅(言えたら勝ち🎉)
- App Checkトークンは
X-Firebase-AppCheckヘッダで送る(URLに入れない)📮🚫 (Firebase) - 自前API側は ヘッダ確認→Admin SDKでverify→失敗は拒否🧱🛡️ (Firebase)
- “本人”まで確定したいなら Auth ID token も verify する🙋♂️🔐 (Firebase)
- 重要APIは limited-use token + consume でリプレイ耐性を上げられる♻️🚫 (Firebase)
次の第19章は、今作った“守り付き自前API”を、Antigravity / Gemini CLI で自動レビュー&改善して「漏れを潰す」フェーズにできます😆🔎 (例:App Check初期化漏れ、直叩き経路、ログにトークン出ちゃってないか、など)