Firexport logo

FirexportBlog

Firebase App Check errors: fix 403s, “App attestation failed” and invalid tokens

Every App Check error happens at one of two steps: your app getting a token from its attestation provider (Play Integrity, App Attest, reCAPTCHA), or a Firebase service checking that token. When the first step fails, the second fails too, so don’t stop at the service’s error: look for the token exchange error and fix your platform’s registration. Emulators, simulators and localhost can’t pass attestation at all, so they use a debug token.

In short

  • Find the step that failed first. A token exchange that ends in a 403 is a provider setup problem; a service rejecting requests with no exchange error means the token is missing or invalid. Tell them apart
  • Use a debug token while developing. Emulators, simulators, localhost and debug-signed builds can’t pass real attestation. How to register one
  • Each platform has values that must match. The signing certificate’s SHA-256 on Android, the Team ID and App Attest’s production environment on Apple, the reCAPTCHA key’s domains on the web. Causes by platform
  • AI Logic has enforced App Check automatically since November 2, 2026. You can postpone it until January 21, 2027 at the latest. What to do

Find the failed step from the message

MessageFailed step
Android: Error returned from API. code: 403 body: App attestation failed.Getting the token. The App Check server didn’t accept the Play Integrity result.
Apple: The server responded with an error … HTTP status code: 403Getting the token. The App Attest or DeviceCheck result wasn’t accepted.
Web: HTTP status: 403. (appCheck/fetch-status-error), then appCheck/throttledGetting the token. The reCAPTCHA result wasn’t accepted, and the SDK won’t retry for 24 hours.
Cloud Storage: Firebase App Check token is invalid. (storage/unauthorized-app in the web SDK)Using the token. It’s missing or invalid.
Callable functions: functions/unauthenticatedUsing the token. A function with enforceAppCheck: true rejected it. A bad Auth token gives the same code; the function’s log line AppCheck token was rejected tells them apart.
Realtime Database: Provided AppCheck credentials for the app named ... are invalidUsing the token. It’s invalid.
Firebase AI Logic: 403 PERMISSION_DENIED: ... you must enforce Firebase App Check.Using the token. See the AI Logic section.

If the app can’t get a token, its service requests carry no valid one (the web SDK sends a placeholder token instead). So when a service rejects requests, check first whether a token exchange error was logged too. After a failure, the SDKs hold off retrying: 24 hours after a 403 or 404 on the web, 24 hours after a 400 or 404 on Android and Apple, and up to 4 hours after other errors. That state lives only in memory, so after you fix the setup, restart the app or reload the page before you check.

Use a debug token while developing

Emulators and simulators don’t count as valid devices, and debug builds that aren’t on Google Play don’t pass Play Integrity. reCAPTCHA keys shouldn’t list localhost. In these environments, turn on the debug provider and register the token it logs in the console.

  1. Turn on the debug provider in development builds only.
    // 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. Run the app and find the debug token in the log. Current SDKs print Firebase App Check debug token: <UUID> (in logcat on Android, the Xcode console on Apple, the browser console on the web).
  3. Register it. In the Firebase console, open App Check, go to the Apps tab, and choose Manage debug tokens from your app’s ⋮ menu. Each app can have up to 20.
  • Tokens change. A new one is made when you clear the app’s data or reinstall on Android, reinstall on Apple, or use another browser profile or clear site data on the web. Register the new one again.
  • In CI, pass a token you registered. Set the token string in self.FIREBASE_APPCHECK_DEBUG_TOKEN on the web, the instrumentation argument firebaseAppCheckDebugSecret on Android, the scheme environment variable AppCheckDebugToken on Apple, and the debugToken parameter in Flutter.
  • Treat the token like a password. Don’t commit it, and keep the debug provider and its token out of production builds.

Causes by platform

Android (Play Integrity)

SymptomCauseFix
Fails only on emulators or debug buildsEmulators aren’t valid devices, and Google Play doesn’t know the debug signature.Debug token
The app from Play failsYou registered the upload key’s SHA-256. With Play App Signing, Google re-signs the app with the app signing key.Register the SHA-256 of the app signing key certificate from the Play Console’s Manage Play app signing page in App Check
An app distributed outside Play failsBy default, only app versions Google Play recognizes (PLAY_RECOGNIZED) pass.In App Check’s Play Integrity settings, set PLAY_RECOGNIZED to Not required and raise the minimum device integrity to Device integrity
Fails as users grow (TOO_MANY_REQUESTS, -8)Cloud projects not linked in the Play Console are capped at 10,000 Play Integrity requests a day.Link the Firebase project under Play Integrity API in the Play Console (Link Cloud project), then request more quota if you need it. Only apps on Google Play can be linked.

Apple (App Attest, DeviceCheck)

SymptomCauseFix
Fails on the SimulatorThe Simulator isn’t a valid device.Debug token
Only builds installed from Xcode failAdding the App Attest capability sets the environment to development, and App Check doesn’t accept results from it. TestFlight and App Store builds always use production.Set App Attest Environment to production in the entitlements file
Fails on every deviceThe Team ID registered in Firebase isn’t the app’s.Enter the right Team ID for the Apple app in the Firebase project settings
Fails on Macs or in app extensionsApp Attest isn’t supported there.Add DeviceCheck as a fallback provider. DeviceCheck needs a key (.p8) made on the Apple Developer site and its key ID registered in App Check
Flutter: the provider you chose isn’t used on real devicesCalling FirebaseApp.configure() in AppDelegate first makes it ignore providerApple.Remove configure() from AppDelegate and use only Firebase.initializeApp() in Dart

Web (reCAPTCHA)

SymptomCauseFix
Fails only on the deployed siteThe domain isn’t in the reCAPTCHA key’s list of domains.Add the domain to the key. It can take up to 30 minutes to apply
Fails on localhostProduction keys don’t list localhost.Debug token
Fails after changing keysThe provider class and the value registered in Firebase don’t match.An Enterprise key takes ReCaptchaEnterpriseProvider in code and the site key in Firebase; a v3 key takes ReCaptchaV3Provider in code and the secret key in Firebase
Still fails after the fixAfter a 403 or 404, the SDK doesn’t retry the token exchange for 24 hours.Reload the page. That state lives only in memory

AI Logic: enforced automatically since November 2, 2026

Since November 2, 2026, Firebase enforces App Check for Firebase AI Logic in projects that weren’t enforcing it. Requests without a valid token are blocked, including those from released app versions without App Check. Two AI Logic errors name App Check:

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.
  • The first means a request without a valid App Check token called a model that’s commonly abused. Set up App Check and enforce it, with the debug provider while developing.
  • The second means the project was judged inactive and doesn’t enforce App Check. If you already enforce it and still see this, check replay protection: when it’s on, even in Monitor only mode, only limited-use tokens count.

If versions without App Check are still in users’ hands, you can postpone enforcement. Change the Enforces date on the Firebase AI Logic row in App Check’s APIs tab; January 21, 2027 is the last date allowed. If the row already says Enforced, change the date, then in that row’s Set up set Baseline protection to Unenforced (monitoring only) and replay protection to Disabled. Google advises against this, so ship a version with App Check before then.

Before you enforce it on other services

  • Read the metrics first. App Check’s APIs tab splits each service’s requests into Verified, Outdated client (no token), Unknown origin and Invalid. Once enforced, only verified requests get through, so enforce when nearly all recent requests are verified.
  • Old app versions get blocked. Versions without the App Check SDK are rejected the moment you enforce.
  • It takes up to 15 minutes to apply. Don’t judge the result right after you turn it on.
  • Cloud Functions can enforce it on callable functions only. Add enforceAppCheck: true and redeploy. onRequest functions aren’t covered by enforcement, so verify the token yourself with the Admin SDK.

Sources

All posts →