Search code examples
firebaserecaptcharecaptcha-v3firebase-app-check

Firebase App Check and reCAPTCHA v3 Enterprise Integration: Billing and Token Reusability


I'm attempting to secure a self-hosted backend for a web app using Firebase App Check with reCAPTCHA v3 Enterprise as the attestation provider, and I have some questions regarding the billing structure for this setup.

When only using reCAPTCHA v3, the standard process is to programmatically invoke a challenge on the client side using grecaptcha.execute, retrieve a token, and then send it to the backend. The backend subsequently verifies the token via an API request to reCAPTCHA's servers. My understanding from the reCAPTCHA Enterprise's pricing page is that I am billed each time I verify a token in the backend.

In contrast, the flow with Firebase App Check appears to be slightly different. Here, the client interacts with reCAPTCHA v3 through Firebase App Check and receives an "attestation" in the form of a token. The client then sends this token to my backend, and my backend verifies the token's validity by making a request to Firebase's servers. Additionally, Firebase App Check tokens have a configurable expiration time and can be reused, with an option to enable replay protection.

Given this, I'm unclear about how the billing works when Firebase App Check is integrated with reCAPTCHA v3. Specifically, I'm wondering:

  1. Am I billed each time Firebase App Check issues a token, or only when I verify the validity of a token issued by Firebase App Check in my backend?
  2. Does the ability to reuse tokens in Firebase App Check potentially reduce costs compared to the traditional reCAPTCHA v3 method where tokens are not reused?

Any insight into these questions would be greatly appreciated.


Solution

  • Firebaser here, and thanks for this question.

    To answer your two questions,

    1. You are not billed when validating App Check tokens in your backend. App Check does not bill you—reCAPTCHA Enterprise does. They will bill you only when App Check calls assessment.create() on your behalf, which occurs when around 50% of an App Check token's TTL has elapsed (if you are using App Check without Replay Protection). If you are using App Check with Replay Protection, you will need to obtain a new App Check token every single time you want to access your protected backend, which in turn means assessment.create() will be invoked every single time, potentially increasing the number of assessments created compared to no Replay Protection. We therefore recommend that you use Replay Protection only on your most security-sensitive endpoints that are accessed at lower volumes.
    2. Yes, this trade-off is a deliberate feature. With App Check's traditional security model (i.e., without Replay Protection), we are forfeiting a degree of security in exchange for reusing the same App Check token throughout a TTL that you can configure. Only one assessment.create() is called per refresh, but keep in mind that the App Check SDK is designed to eagerly refresh the token when approximately 50% of the TTL has elapsed (effectively refreshing at about twice the rate of your configured TTL). You can adjust this TTL in the Firebase console.

    If you are interested in a more detailed response, including interactions with the new Replay Protection feature, please see below.

    I noticed that your post mentions both reCAPTCHA v3 and reCAPTCHA Enterprise, so let's start by noting that there is a difference between them:

    • reCAPTCHA v3 is free and has a 1,000,000 monthly limit on the number of assessments you can make, and to exceed that limit, you must either migrate to reCAPTCHA Enterprise or apply for an exemption, subject to approval. It also has no support or SLAs.
    • reCAPTCHA Enterprise is free up to 1,000,000 monthly calls, and at-cost beyond that. You are correct in that the exact number of times your server calls assessments.create is what determines the amount you are billed. It also includes Basic Support and a 99.9%+ uptime SLA.

    For the remainder of my response, I will assume that you are referring to reCAPTCHA Enterprise (and not reCAPTCHA v3) in your post.

    Let's discuss App Check with reCAPTCHA Enterprise as your attestation provider. The basic client-side flow (without Replay Protection) is as follows:

    • Your application uses the App Check SDK to manage an App Check token in the background.
    • Before the App Check token expires, the token will be automatically refreshed using the following token exchange procedure. (Note: the App Check SDK is designed to refresh the App Check token when about 50% of its TTL has elapsed. Keep this in mind when estimating the number of times your application will create assessments.)
      1. Call grecaptcha.enterprise.execute() to get a reCAPTCHA Enterprise token.
      2. This reCAPTCHA Enterprise token is sent to the App Check server.
      3. The App Check server calls assessment.create() on your behalf and reads the assessment to ensure that the reCAPTCHA Enterprise token is valid.
      4. If valid, a new App Check token is created and returned to the SDK.
    • Whenever your application needs to send a request to an App Check protected backend endpoint, you can retrieve the current App Check token from the App Check SDK and send it along with the request (usually as the header X-Firebase-AppCheck). If your application is using an official Firebase SDK to communicate with an App Check protected Firebase backend, this step is automatically done for you.

    What this means is that App Check (without Replay Protection) essentially employs a session-based model, where a valid App Check token is the proof of an attested app session, and it is valid as long as it has not expired.

    Next, let's talk about the basic server-side flow. We recommend that you use the Firebase Admin SDK to perform the following steps.

    • Your server receives a request from your application along with an App Check token.
    • Your server validates the App Check token using the Admin SDK. This step does not require sending the token to the App Check backend (but it does retrieve the public keys from the App Check servers once in a while, which is handled automatically by the Admin SDK). This specific App Check token validation is at no cost to you.

    By using App Check's session-based model, you are making a trade-off between multiple factors compared to a direct integration with reCAPTCHA Enterprise. Here we list all the dimensions that you should consider:

    • Security. Note that a direct integration with reCAPTCHA Enterprise will have built-in replay protection. That is, when two separate assessments are created for the same reCAPTCHA Enterprise token, the second one would show up as invalid.
    • Quota and billing. What you gain by forfeiting the intrinsic replay protection of reCAPTCHA Enterprise tokens is a potential decrease in the number of assessments created, depending on your traffic patterns. No matter how many times the user needs to access your protected backend before the App Check token reaches the refresh point, that user only needs 1 assessment.
    • Performance. Since attestation provider handshakes are not free to run, they can impact performance, especially on mobile devices. By using App Check tokens in a background refresh, the on-device latency just before a protected action is made is eliminated.
    • Federated providers. Since App Check sits in between the attestation provider and your server as a federated abstraction layer, your server no longer needs to worry about validating tokens from different attestation providers. It only needs to understand one kind of token: App Check tokens. This means you can program your server to serve all platforms with the same code (e.g., Web, Android devices, and Apple devices). The App Check server and SDKs will handle the token exchange process. If none of the out-of-the-box attestation providers work for your intended platform, you can even set up your own custom provider.

    The trade-off on some of these factors can also be adjusted by increasing or decreasing the App Check token's TTL.

    So far we've talked about the traditional session-based model, but as you have rightly pointed out, we recently launched the new Replay Protection feature. This new feature uses an entirely different model, one that's very similar to a direct integration with reCAPTCHA Enterprise: every call to a Replay Protected endpoint must invoke a fresh attestation. By definition, in the trade-off list above, we've made the choice to be as secure as possible while sacrificing performance and billing, but note that crucially the federation advantage remains. Another key difference is that, unlike the traditional session-based model, the Admin SDK will need to contact the Firebase App Check backend to verify that the token has not been previously consumed. However, even so, this verification is still at no cost to you.

    This feature is available now on Cloud Functions for Firebase as well as your own backends. We recommend that developers use this feature to protect only their most security-sensitive endpoints that are accessed at lower volumes, since it can potentially create more assessments than App Check's traditional model (because every call requires a new assessment, just like a direct integration with reCAPTCHA Enterprise).

    [Edited to fix some omissions.]