Firebase App Check のエラー解決: 403、App attestation failed、無効なトークン
App Check のエラーは、2 つの段階のどちらかで起きます。アプリが証明書プロバイダ(Play Integrity、App Attest、reCAPTCHA)を使ってトークンを受け取る段階か、Firebase のサービスがそのトークンを確認する段階です。前の段階が失敗すると後の段階も失敗するので、サービスのエラーだけを見ずに、まずトークン交換のエラーを探して、プラットフォームごとの登録値を直してください。エミュレータ、シミュレータ、localhost はそもそも証明を通過できないので、デバッグ トークンを使います。
要点
- まず、失敗した段階を見つけます。トークン交換が 403 で終わったならプロバイダの設定の問題で、交換のエラーがないままサービスだけが拒否するなら、トークンがないか無効です。メッセージで見分ける
- 開発環境ではデバッグ トークンを使います。エミュレータ、シミュレータ、localhost、デバッグ署名のビルドは、実際の証明を通過できません。登録方法
- プラットフォームごとに合わせるべき値があります。Android は署名証明書の SHA-256、Apple は Team ID と App Attest の production 環境、ウェブは reCAPTCHA キーのドメインです。プラットフォーム別の原因
- AI Logic には 2026 年 11 月 2 日から App Check が自動で適用されます。延期できるのは 2027 年 1 月 21 日までです。対応方法
メッセージから失敗した段階を見つける
| メッセージ | 失敗した段階 |
|---|---|
Android: Error returned from API. code: 403 body: App attestation failed. | トークンの取得。App Check サーバーが Play Integrity の結果を受け付けませんでした。 |
Apple: The server responded with an error … HTTP status code: 403 | トークンの取得。App Attest または DeviceCheck の結果が受け付けられませんでした。 |
ウェブ: HTTP status: 403. (appCheck/fetch-status-error)、続いて appCheck/throttled | トークンの取得。reCAPTCHA の結果が受け付けられず、SDK は 24 時間、再試行しません。 |
Cloud Storage: Firebase App Check token is invalid.(ウェブ SDK では storage/unauthorized-app) | トークンの使用。トークンがないか、無効です。 |
呼び出し可能関数(callable): functions/unauthenticated | トークンの使用。enforceAppCheck: true の関数が拒否しました。Auth トークンが正しくないときと同じコードなので、関数のログの AppCheck token was rejected で見分けます。 |
Realtime Database: Provided AppCheck credentials for the app named ... are invalid | トークンの使用。トークンが無効です。 |
Firebase AI Logic: 403 PERMISSION_DENIED: ... you must enforce Firebase App Check. | トークンの使用。AI Logic の節を参照してください。 |
トークンを取得できないと、サービスへのリクエストには有効なトークンが付きません(ウェブ SDK はプレースホルダ トークンを付けて送ります)。そのため、サービス側のエラーが出ていても、トークン取得のエラーが一緒に記録されていないかをまず確認してください。失敗したあと、SDK は再試行を遅らせます。ウェブは 403・404 のあと 24 時間、Android と Apple は 400・404 のあと 24 時間、それ以外のエラーは最大 4 時間です。この状態はメモリ上にしかないので、設定を直したら、アプリを再起動するかページを再読み込みしてから確認してください。
開発中はデバッグ トークンを使う
エミュレータとシミュレータは有効なデバイスとして認められず、Google Play で配信されていないデバッグ ビルドは Play Integrity を通過できません。reCAPTCHA キーには localhost を入れないのが原則です。こうした環境では、デバッグ プロバイダを有効にして、ログに出力されたトークンをコンソールに登録します。
- 開発ビルドでだけデバッグ プロバイダを有効にします。
// Android (Kotlin): com.google.firebase:firebase-appcheck-debug Firebase.appCheck.installAppCheckProviderFactory( if (BuildConfig.DEBUG) DebugAppCheckProviderFactory.getInstance() else PlayIntegrityAppCheckProviderFactory.getInstance(), ) // iOS (Swift): before FirebaseApp.configure() #if DEBUG AppCheck.setAppCheckProviderFactory(AppCheckDebugProviderFactory()) #endif // Web: before initializeAppCheck(), in development builds only self.FIREBASE_APPCHECK_DEBUG_TOKEN = true; // Flutter (firebase_app_check 0.5+) await FirebaseAppCheck.instance.activate( providerAndroid: kDebugMode ? const AndroidDebugProvider() : const AndroidPlayIntegrityProvider(), providerApple: kDebugMode ? const AppleDebugProvider() : const AppleAppAttestWithDeviceCheckFallbackProvider(), ); - アプリを実行し、ログで debug token を探します。最新の SDK は
Firebase App Check debug token: <UUID>の形式で出力します(Android は logcat、Apple は Xcode のコンソール、ウェブはブラウザのコンソール)。 - トークンを登録します。Firebase コンソールの App Check でアプリ(Apps)タブを開き、アプリの ⋮ メニューからデバッグ トークンを管理(Manage debug tokens)を選びます。アプリごとに 20 個まで登録できます。
- トークンは変わります。Android はアプリのデータを消去するか再インストールすると、Apple は再インストールすると、ウェブは別のブラウザ プロファイルを使うかサイトのデータを消去すると、新しいトークンが生成されます。新しいトークンは登録し直す必要があります。
- CI では登録済みのトークンを渡します。ウェブは
self.FIREBASE_APPCHECK_DEBUG_TOKENにトークンの文字列を入れ、Android はインストルメンテーション テストの引数firebaseAppCheckDebugSecret、Apple は scheme の環境変数AppCheckDebugToken、Flutter はdebugTokenパラメータを使います。 - トークンはパスワードと同じように扱います。リポジトリにコミットせず、デバッグ プロバイダとトークンを本番ビルドに含めないでください。
プラットフォーム別の原因
Android(Play Integrity)
| 症状 | 原因 | 対処 |
|---|---|---|
| エミュレータやデバッグ ビルドでだけ失敗 | エミュレータは有効なデバイスではなく、デバッグ署名は Google Play が知りません。 | デバッグ トークン |
| Play からインストールしたアプリが失敗 | アップロード鍵の SHA-256 を登録しています。Play アプリ署名を使うと、Google がアプリ署名鍵で署名し直します。 | Play Console の Play アプリ署名に移動(Manage Play app signing)で開くページから、アプリ署名鍵の証明書の SHA-256 を App Check に登録 |
| Play 以外で配布したアプリが失敗 | デフォルトの設定では、Google Play が認識しているアプリのバージョン(PLAY_RECOGNIZED)しか通りません。 | App Check の Play Integrity 設定で PLAY_RECOGNIZED を不要(Not required)にし、デバイスの完全性の最小レベルをデバイスの完全性(Device integrity)に上げる |
ユーザーが増えるにつれて失敗(TOO_MANY_REQUESTS、-8) | Play Console にリンクされていない Cloud プロジェクトは、Play Integrity のリクエストが 1 日 1 万件に制限されます。 | Play Console の Play Integrity API の項目で、Cloud プロジェクトをリンク(Link Cloud project)から Firebase プロジェクトをリンクし、必要なら割り当ての増加をリクエスト。リンクできるのは Google Play にあるアプリだけです。 |
Apple(App Attest、DeviceCheck)
| 症状 | 原因 | 対処 |
|---|---|---|
| シミュレータで失敗 | シミュレータは有効なデバイスではありません。 | デバッグ トークン |
| Xcode からインストールしたビルドだけが失敗 | App Attest capability を追加すると環境が development になりますが、App Check はこの環境の結果を受け付けません。TestFlight と App Store のビルドは常に production です。 | entitlements ファイルの App Attest Environment を production に |
| すべてのデバイスで失敗 | Firebase に登録した Team ID がアプリのものと違います。 | Firebase のプロジェクトの設定で、Apple アプリに正しい Team ID を入力 |
| Mac や App Extension で失敗 | App Attest に対応していない環境です。 | DeviceCheck をフォールバックのプロバイダとして追加。DeviceCheck は、Apple デベロッパー サイトで作成した秘密鍵(.p8)とそのキー ID を App Check に登録 |
| Flutter: 選んだプロバイダが実機で使われない | AppDelegate で FirebaseApp.configure() を先に呼ぶと、providerApple が無視されます。 | AppDelegate の configure() を削除し、Dart の Firebase.initializeApp() だけを使う |
ウェブ(reCAPTCHA)
| 症状 | 原因 | 対処 |
|---|---|---|
| デプロイしたサイトでだけ失敗 | そのドメインが reCAPTCHA キーのドメイン リストにありません。 | キーの設定にドメインを追加。反映まで最大 30 分 |
| localhost で失敗 | 本番用のキーには localhost を入れません。 | デバッグ トークン |
| キーを変えたあとに失敗 | プロバイダのクラスと Firebase に登録した値の組み合わせが合っていません。 | Enterprise キーはコードに ReCaptchaEnterpriseProvider、Firebase にサイトキー。v3 キーはコードに ReCaptchaV3Provider、Firebase に秘密鍵 |
| 直したのに失敗が続く | 403・404 のあとは、SDK が 24 時間、トークン交換を再試行しません。 | ページを再読み込み。この状態はメモリ上にしかありません。 |
AI Logic: 2026 年 11 月 2 日から自動で適用
Firebase は 2026 年 11 月 2 日から、App Check を適用していなかったプロジェクトの Firebase AI Logic に、App Check を自動で適用しています。有効なトークンのないリクエストはブロックされ、App Check を組み込まずにリリースしたアプリのバージョンも同じです。App Check に触れている AI Logic のエラーは 2 つあります。
403 PERMISSION_DENIED: To access this model, you must enforce
Firebase App Check.
403 PERMISSION_DENIED: Firebase AI Logic has been deactivated in this
project. To resume using Firebase AI Logic, you must enforce Firebase
App Check.- 1 つ目は、有効な App Check トークンなしで、不正使用の多いモデルを呼び出した場合です。App Check を設定して適用してください。開発中はデバッグ プロバイダを使います。
- 2 つ目は、プロジェクトが非アクティブと判定され、App Check を適用していない場合です。すでに適用しているのに出るなら、リプレイ保護(replay protection)を確認してください。有効になっていると(Monitor only モードを含む)、限定使用のトークン(limited-use token)しか認められません。
App Check のないバージョンがまだユーザーの手元にあるなら、適用を延期できます。App Check の API(APIs)タブで Firebase AI Logic の行の Enforces の日付を変えればよく、2027 年 1 月 21 日が最終日です。すでに適用済み(Enforced)なら、日付を変えたうえで、その行の設定(Set up)で基本保護(Baseline protection)を Unenforced (monitoring only) に、リプレイ保護を Disabled に変えないと解除されません。Google が推奨していない方法なので、それまでに App Check を組み込んだバージョンをリリースしてください。
ほかのサービスに適用する前に
- まず指標を見ます。App Check の API(APIs)タブでは、サービスごとのリクエストが確認済み(Verified)、古いクライアント(Outdated client、トークンなし)、送信元が不明(Unknown origin)、無効(Invalid)に分けて表示されます。適用すると確認済みのリクエストしか通らないので、最近のリクエストのほとんどが確認済みになってから適用しましょう。
- 古いバージョンのアプリはブロックされます。App Check SDK を含まないバージョンは、適用した瞬間からリクエストが拒否されます。
- 反映まで最大 15 分かかります。適用を有効にした直後に結果を判断しないでください。
- Cloud Functions で適用できるのは呼び出し可能関数だけです。
enforceAppCheck: trueを追加して再デプロイすると適用されます。onRequest関数は App Check の適用の対象外なので、Admin SDK でトークンを自分で検証する必要があります。
出典
- App Check の概要、適用を有効にする、指標のモニタリング、デバッグ トークンの上限(REST)
- Play Integrity プロバイダ、Play Integrity の割り当て、Android のデバッグ プロバイダ
- App Attest プロバイダ、DeviceCheck プロバイダ、Apple のデバッグ プロバイダ、App Attest の環境(Apple)、App Attest を使える環境(Apple)
- reCAPTCHA Enterprise プロバイダ、reCAPTCHA v3 プロバイダ、reCAPTCHA キーの作成、ウェブのデバッグ プロバイダ
- Flutter のデバッグ プロバイダ、
firebase_app_checkのactivate() - AI Logic の App Check、AI Logic のエラーコード、Cloud Functions の App Check、独自のバックエンドでのトークンの検証
- SDK のソース: ウェブの再試行制限、ウェブのプレースホルダ トークン、Storage での拒否、Android のエラー メッセージ、Android の再試行、Apple の再試行、呼び出し可能関数での拒否
