Firexportブログ

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 を入れないのが原則です。こうした環境では、デバッグ プロバイダを有効にして、ログに出力されたトークンをコンソールに登録します。

  1. 開発ビルドでだけデバッグ プロバイダを有効にします。
    // 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(),
    );
  2. アプリを実行し、ログで debug token を探します。最新の SDK は Firebase App Check debug token: <UUID> の形式で出力します(Android は logcat、Apple は Xcode のコンソール、ウェブはブラウザのコンソール)。
  3. トークンを登録します。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 でトークンを自分で検証する必要があります。

出典

すべての記事 →