<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Göktuğ Özdemir</title>
    <description>The latest articles on DEV Community by Göktuğ Özdemir (@bgoktugozdemir).</description>
    <link>https://dev.to/bgoktugozdemir</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3034168%2F31b71877-bf95-4e58-a92f-5be2bb362636.png</url>
      <title>DEV Community: Göktuğ Özdemir</title>
      <link>https://dev.to/bgoktugozdemir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bgoktugozdemir"/>
    <language>en</language>
    <item>
      <title>Firebase App Check: Protecting Your Backend from Abuse</title>
      <dc:creator>Göktuğ Özdemir</dc:creator>
      <pubDate>Tue, 17 Mar 2026 12:00:00 +0000</pubDate>
      <link>https://dev.to/bgoktugozdemir/firebase-app-check-protecting-your-backend-from-abuse-2401</link>
      <guid>https://dev.to/bgoktugozdemir/firebase-app-check-protecting-your-backend-from-abuse-2401</guid>
      <description>&lt;p&gt;I'm Berat Göktuğ Özdemir, a Senior Flutter Developer since 2018 and a Google Developer Expert for Firebase. I regularly speak at DevFest events about Flutter and Firebase.&lt;/p&gt;

&lt;p&gt;In this post, I take a deep dive into Firebase App Check: why you need it, how attestation providers work across platforms, and a full Flutter implementation guide with debug provider setup, troubleshooting tips, and monitoring strategy. If you're building with Firebase and haven't set up App Check yet, this one's for you.&lt;/p&gt;

&lt;p&gt;As developers, we spend a lot of time building amazing user experiences, but backend security is often an afterthought until it's too late. When using serverless technologies like Firebase, your API endpoints and databases are inherently exposed to the internet.&lt;/p&gt;

&lt;p&gt;How can you ensure that the requests hitting your Firebase project are actually coming from &lt;em&gt;your&lt;/em&gt; authentic app and not a malicious script, a bot, or a tampered client? This is where &lt;strong&gt;Firebase App Check&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Firebase App Check?
&lt;/h2&gt;

&lt;p&gt;In client applications, some Firebase configuration values must ship with the app. That often leads developers to assume their backend is safe as long as those values are “just config”. In reality, attackers can still script requests, abuse quotas, and target exposed endpoints unless additional protection is in place.&lt;/p&gt;

&lt;p&gt;The issue is usually not that Firebase API keys are secret credentials that must be hidden at all costs. The real problem is that &lt;strong&gt;public client configuration alone cannot prove that a request truly comes from your untampered app&lt;/strong&gt;. Anyone can extract these details and use them in a custom script, a bot, or a modified client to send unauthorized requests, manipulate your database, or exhaust your quotas. Do you know how you can block these unauthorized clients?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is where Firebase App Check comes into play.&lt;/strong&gt; It solves this exact problem by using a platform-specific app and device attestation to verify the client is valid. The diagram summarizes the behavior of the App Check between your app and Firebase services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwp2vy1ge7xr5tab0wflw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwp2vy1ge7xr5tab0wflw.png" alt="Diagram showing Firebase App Check acting as a security gate between an app and the backend: a green “User Request” is verified and allowed through to the backend servers, while a red “Bad Request” is rejected and blocked." width="600" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Green User (User Request):&lt;/strong&gt; A real user of your app. App Check validates the request and delivers it securely to the backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Red User (Bad Request):&lt;/strong&gt; A copied APK, emulator, bot, or an unauthorized request from a client. App Check blocks this request and prevents access to the backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The role of App Check:&lt;/strong&gt; All requests must pass App Check validation. Only validated requests can access the backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should we use App Check?
&lt;/h2&gt;

&lt;p&gt;There are a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Significantly mitigates the risk of backend abuse from unauthorized clients.&lt;/li&gt;
&lt;li&gt;Detects and prevents bot and automation attacks.&lt;/li&gt;
&lt;li&gt;Protects real users and guards against the abuse of free and sensitive resources.&lt;/li&gt;
&lt;li&gt;Only authorized apps with verified integrity can access your Firebase services.&lt;/li&gt;
&lt;li&gt;App Check provides layered protection by working together with your security rules and authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; App Check is a powerful gatekeeper between your app and Firebase services. &lt;br&gt;
&lt;strong&gt;App Check significantly raises the bar by allowing only requests with valid attestation to reach protected resources, but it should be treated as one layer in a broader security strategy.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Does It Work?
&lt;/h2&gt;

&lt;p&gt;Firebase App Check relies on platform-specific services called &lt;strong&gt;Attestation Providers&lt;/strong&gt; to verify device and app authenticity.&lt;/p&gt;

&lt;p&gt;Instead of blindly trusting incoming requests, App Check forces the client app to prove its identity before it even reaches your database or backend logic. Here are the default providers used for different platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Android:&lt;/strong&gt; &lt;a href="https://developer.android.com/google/play/integrity" rel="noopener noreferrer"&gt;Play Integrity API&lt;/a&gt; (replaces the deprecated SafetyNet). It checks if the app is installed from the Google Play Store and is running on a genuine, unrooted Android device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apple (iOS/macOS):&lt;/strong&gt; &lt;a href="https://developer.apple.com/documentation/devicecheck" rel="noopener noreferrer"&gt;DeviceCheck&lt;/a&gt; or &lt;a href="https://developer.apple.com/documentation/devicecheck/preparing_to_use_the_app_attest_service" rel="noopener noreferrer"&gt;App Attest&lt;/a&gt;. These Apple services cryptographically verify that the request is coming from a legitimate Apple device and your authentic app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web:&lt;/strong&gt; &lt;a href="https://developers.google.com/recaptcha/docs/v3" rel="noopener noreferrer"&gt;reCAPTCHA v3&lt;/a&gt; or &lt;a href="https://cloud.google.com/recaptcha-enterprise" rel="noopener noreferrer"&gt;reCAPTCHA Enterprise&lt;/a&gt;. It uses advanced risk analysis engines to distinguish between human (or legitimate browser) traffic and automated bots, without showing annoying image puzzles to the user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Providers:&lt;/strong&gt; If you are building for platforms like desktop (Windows/macOS/Linux) or IoT devices, you can create a &lt;a href="https://firebase.google.com/docs/app-check/custom-provider" rel="noopener noreferrer"&gt;Custom Attestation Provider&lt;/a&gt; using your own backend logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Workflow:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Your app requests an attestation token from the platform's provider (e.g., Play Integrity).&lt;/li&gt;
&lt;li&gt;The provider evaluates the device and app integrity. If valid, it returns a short-lived App Check token.&lt;/li&gt;
&lt;li&gt;Your app attaches this token to every subsequent request made to Firebase services.&lt;/li&gt;
&lt;li&gt;The Firebase backend evaluates the token. If it's valid, the request proceeds. If not, it is instantly rejected.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Quotas and Limits (Token TTL)
&lt;/h3&gt;

&lt;p&gt;When developers first hear about App Check, a common concern is: &lt;em&gt;"Will my app hit the provider's API limits?"&lt;/em&gt; It is important to understand that &lt;strong&gt;your app does not contact the attestation provider for every single database read/write&lt;/strong&gt;. Instead, the generated App Check token has a &lt;strong&gt;Time-To-Live (TTL)&lt;/strong&gt;. By default, this is 1 hour. The client SDK automatically caches this token and only requests a new one from the provider when it is about to expire.&lt;/p&gt;

&lt;p&gt;However, your use of App Check is still subject to the &lt;a href="https://firebase.google.com/docs/app-check#quotas_limits" rel="noopener noreferrer"&gt;quotas of the underlying attestation providers&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Play Integrity (Android):&lt;/strong&gt; Has a default daily quota of 10,000 calls for its &lt;a href="https://developer.android.com/google/play/integrity/overview#usage-tiers" rel="noopener noreferrer"&gt;Standard API usage tier&lt;/a&gt;. If your app has a large user base and you expect to exceed this, you must &lt;a href="https://developer.android.com/google/play/integrity/setup#increase-daily" rel="noopener noreferrer"&gt;request a daily limit increase&lt;/a&gt;. You can do this by directly submitting the &lt;a href="https://support.google.com/googleplay/android-developer/contact/piaqr" rel="noopener noreferrer"&gt;Play Integrity API Quota Request form&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeviceCheck / App Attest (Apple):&lt;/strong&gt; Apple does not publicly publish hard limits for these services, but they are generally high enough to support massive, production-scale applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;reCAPTCHA Enterprise (Web):&lt;/strong&gt; Offers 10,000 assessments per month at no cost. Beyond that, standard Google Cloud pricing applies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behind the scenes, the Firebase SDK automatically refreshes the token before the TTL expires, requiring no manual intervention from the developer. If a network error occurs during this auto-refresh process, the pending request may fail, but it will be handled gracefully by standard Firebase SDK error mechanisms. This means you don't need to write custom token retry logic; you just handle standard Firebase network errors as you normally would.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Services Are Protected?
&lt;/h2&gt;

&lt;p&gt;App Check has built-in, seamless support for several core Firebase products. Once enabled and enforced in the Firebase Console, it automatically intercepts and verifies traffic for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Firestore Database &amp;amp; Realtime Database:&lt;/strong&gt; Prevents unauthorized data access, scraping, and malicious database modifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Storage for Firebase:&lt;/strong&gt; Protects your files and prevents attackers from exhausting your storage and download bandwidth quotas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Functions for Firebase (callable functions only):&lt;/strong&gt; Helps ensure that your callable endpoints are invoked only by legitimate clients. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase Authentication:&lt;/strong&gt; Prevents malicious or automated account creation and protects your project from SMS fraud/abuse (especially critical and costly if you use Phone Authentication).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase AI Logic:&lt;/strong&gt; Protects your access to AI models, preventing unexpected billing spikes caused by bot-driven API calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What about Custom Backends?&lt;/strong&gt;&lt;br&gt;
You are not limited to Firebase services! If you have your own custom API (e.g., a Node.js, Python, or Go server), you can use the &lt;a href="https://firebase.google.com/docs/app-check/custom-resource-backend" rel="noopener noreferrer"&gt;Firebase Admin SDK&lt;/a&gt; to intercept incoming requests and verify the App Check tokens before processing them.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Implement App Check
&lt;/h2&gt;

&lt;p&gt;Implementing App Check in a Flutter application involves configuring your Firebase project and adding a few lines of code to your app's initialization.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Register Your Apps
&lt;/h3&gt;

&lt;p&gt;Before writing any code, you need to register your apps in the Firebase Console:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your Firebase project.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Build &amp;gt; App Check&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Apps&lt;/strong&gt; tab and register your Android, iOS, and Web applications with their respective providers (Play Integrity for Android, App Attest for iOS, and reCAPTCHA for Web).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Step 2: Add the Flutter Dependency
&lt;/h3&gt;

&lt;p&gt;Add the &lt;code&gt;firebase_app_check&lt;/code&gt; plugin to your Flutter project using your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub add firebase_app_check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Initialize App Check
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;main.dart&lt;/code&gt; file, you need to initialize App Check right after initializing Firebase. Specify which providers to use for each platform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// I assume you already added this line&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Initialize Firebase First&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Firebase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;options:&lt;/span&gt; &lt;span class="n"&gt;DefaultFirebaseOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentPlatform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Initialize App Check&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;FirebaseAppCheck&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// For Android: Default provider for Android is the Play Integrity provider.&lt;/span&gt;
    &lt;span class="c1"&gt;// You can use the "AndroidProvider" enum to choose&lt;/span&gt;
    &lt;span class="c1"&gt;// your preferred provider. Choose from:&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Debug provider&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. Safety Net provider&lt;/span&gt;
    &lt;span class="c1"&gt;// 3. Play Integrity provider&lt;/span&gt;
    &lt;span class="nl"&gt;androidProvider:&lt;/span&gt; &lt;span class="n"&gt;kDebugMode&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;AndroidProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AndroidProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;playIntegrity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// For iOS: Default provider for iOS/macOS is the Device Check provider.&lt;/span&gt;
    &lt;span class="c1"&gt;// You can use the "AppleProvider" enum to choose&lt;/span&gt;
    &lt;span class="c1"&gt;// your preferred provider. Choose from:&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Debug provider&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. Device Check provider&lt;/span&gt;
    &lt;span class="c1"&gt;// 3. App Attest provider&lt;/span&gt;
    &lt;span class="c1"&gt;// 4. App Attest provider with fallback to Device Check provider (App Attest provider is only available on iOS 14.0+, macOS 14.0+)&lt;/span&gt;
    &lt;span class="nl"&gt;appleProvider:&lt;/span&gt; &lt;span class="n"&gt;kDebugMode&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;AppleProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AppleProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;appAttest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// For Web: You can also use a `ReCaptchaEnterpriseProvider` provider &lt;/span&gt;
    &lt;span class="c1"&gt;// instance as an argument for `webProvider`&lt;/span&gt;
    &lt;span class="nl"&gt;webProvider:&lt;/span&gt; &lt;span class="n"&gt;ReCaptchaV3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'YOUR_RECAPTCHA_V3_SITE_KEY'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Applying App Check to Specific Services
&lt;/h3&gt;

&lt;p&gt;For most core Firebase services (like Firestore Database, Realtime Database, and Cloud Storage), calling &lt;code&gt;activate()&lt;/code&gt; in your &lt;code&gt;main&lt;/code&gt; function is all you need. The SDKs will automatically handle the App Check tokens under the hood.&lt;/p&gt;

&lt;p&gt;However, for certain specific services (like &lt;strong&gt;Firebase AI Logic&lt;/strong&gt;), you might need to explicitly pass the App Check instance.&lt;/p&gt;

&lt;p&gt;Here is a simple example showing how to use both Firestore Database and Firebase AI Logic in your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Firestore Database&lt;/span&gt;
&lt;span class="c1"&gt;// App Check is automatically applied under the hood.&lt;/span&gt;
&lt;span class="c1"&gt;// You don't need to pass the App Check instance manually.&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;firestore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirebaseFirestore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Firebase AI Logic&lt;/span&gt;
&lt;span class="c1"&gt;// You can explicitly pass the App Check instance to secure your AI calls.&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;googleAI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirebaseAI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;googleAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;appCheck:&lt;/span&gt; &lt;span class="n"&gt;FirebaseAppCheck&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;vertexAI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirebaseAI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vertexAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;appCheck:&lt;/span&gt; &lt;span class="n"&gt;FirebaseAppCheck&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Monitor and Enforce
&lt;/h3&gt;

&lt;p&gt;Once you have released your app with the App Check SDK included, you should &lt;strong&gt;not&lt;/strong&gt; enforce it immediately. Doing so would instantly block older versions of your app that do not have the App Check code yet.&lt;/p&gt;

&lt;p&gt;Instead, go to the App Check dashboard in the Firebase Console and monitor your metrics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92z1b1rscn7d5qosxljw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92z1b1rscn7d5qosxljw.png" alt="Screenshot of the Firebase Console (Cloud Firestore) “App Check request metrics” panel for the last 7 days (Feb 21–Mar 1), showing 0 verified requests out of 200 total and 100% “Unverified: outdated client requests” (200/200), with the graph spiking to 100% near Mar 1 and an “Enforce” button at bottom right." width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the dashboard above, you can track the percentage of &lt;strong&gt;Verified requests&lt;/strong&gt;, &lt;strong&gt;Unverified requests&lt;/strong&gt;, and &lt;strong&gt;Invalid requests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once the vast majority of your traffic falls under "Verified requests" (meaning most of your users have updated to the app version that includes App Check), you can safely click the &lt;strong&gt;Enforce&lt;/strong&gt; button for your backend services (like Firestore Database or Cloud Storage).&lt;/p&gt;

&lt;p&gt;From that moment on, any unverified requests will be blocked by Firebase. If a client app attempts to access an enforced service without a valid App Check token, the request will be rejected, and the developer/user will encounter a permission error like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Uncaught Error in snapshot listener: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Pitfalls &amp;amp; Troubleshooting
&lt;/h2&gt;

&lt;p&gt;While App Check is relatively easy to set up, developers often run into a few common issues during development and deployment. Here are the most frequent ones and how to solve them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Missing or insufficient permissions" error after enforcement:&lt;/strong&gt; If your app was working fine, but suddenly starts throwing &lt;code&gt;FirebaseError: [code=permission-denied]: Missing or insufficient permissions.&lt;/code&gt; right after you clicked "Enforce" in the console.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Solution:&lt;/em&gt; This means App Check is actively blocking your requests. Ensure the App Check SDK is initialized properly before making any calls to Firebase services. Keep in mind that this exact error is also thrown by Firebase Security Rules, so if your security rules are correct, the culprit is likely a missing or invalid App Check token.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Testing on Emulators or Localhost fails:&lt;/strong&gt; By design, App Check blocks traffic from unverified environments, such as the Android Emulator, iOS Simulator, or your local web server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Solution:&lt;/em&gt; Use the Debug Provider for local development. When you run your app in debug mode (&lt;code&gt;kDebugMode&lt;/code&gt;), the SDK prints a secret debug token to your IDE's console (or to Chrome Developer Tools for Web). It looks exactly like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App Check debug token: 55183c20-de61-4438-85e6-8065789265be. You will need to add it to your app's App Check settings in the Firebase console for it to work.
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You must copy this token, go to the &lt;strong&gt;Firebase Console &amp;gt; App Check &amp;gt; Apps&lt;/strong&gt;, click on the three dots next to your app, and select &lt;strong&gt;Manage debug tokens&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32grn0lbyk9nv82mebfp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32grn0lbyk9nv82mebfp.png" alt="Screenshot of the Firebase Console's App Check page on the Apps tab, showing a registered " width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste your token there and save it. This will allow your local environment to bypass the attestation checks securely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkuymhwzo3o9hislm68e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkuymhwzo3o9hislm68e.png" alt="Screenshot of Firebase Console “Manage debug tokens” dialog for App Check, showing fields to name a token (“My Token”) and a generated debug token value (a UUID), with a warning that the token won’t be shown again and buttons for Cancel and Save." width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;"Unverified: invalid requests" spikes on Android:&lt;/strong&gt; This usually happens if there is a mismatch with your app signing keys.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Solution:&lt;/em&gt; Ensure that you have added all your &lt;strong&gt;SHA-256 fingerprints&lt;/strong&gt; (both for debug and release keystores) to your Android app settings in the Firebase Console.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Breaking older app versions:&lt;/strong&gt; Clicking the "Enforce" button too early locks out users who haven't updated their app in the App Store or on Google Play.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Solution:&lt;/em&gt; Always monitor your App Check metrics for a few weeks. Only enforce when the percentage of "Unverified: outdated client requests" drops to an acceptable minimum.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Firebase App Check is an essential, easy-to-implement security layer that protects your backend infrastructure from abuse, billing fraud, and unauthorized access. By ensuring that only your authentic apps can communicate with Firebase services, you add a critical safeguard alongside your existing security rules and authentication methods. Remember to monitor your traffic before enforcing it to ensure a smooth transition for your users.&lt;/p&gt;




&lt;p&gt;Thanks for your time!&lt;/p&gt;

&lt;p&gt;A special thanks to &lt;a href="https://dev.to/thatfiredev"&gt;Rosario&lt;/a&gt;, who inspired me to write this article.&lt;/p&gt;

&lt;p&gt;If you found this article helpful, stay tuned for my next post, where I'll dive into Firebase AI Logic and show how the App Check plays a critical role in securing your AI endpoints.&lt;/p&gt;

&lt;p&gt;You can find me on &lt;a href="https://twitter.com/bgoktugozdemir" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://linkedin.com/in/bgoktugozdemir" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. You can find everything about me here.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/app-check" rel="noopener noreferrer"&gt;Firebase App Check Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/google/play/integrity/overview" rel="noopener noreferrer"&gt;Play Integrity API Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/devicecheck" rel="noopener noreferrer"&gt;Apple DeviceCheck Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/recaptcha-enterprise" rel="noopener noreferrer"&gt;reCAPTCHA Enterprise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/codelabs/appcheck-web" rel="noopener noreferrer"&gt;App Check Web Codelab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>firebase</category>
      <category>appcheck</category>
      <category>flutter</category>
      <category>dart</category>
    </item>
  </channel>
</rss>
