Protect custom backend resources with App Check in web apps

You can use App Check to protect non-Google custom backend resources for your app, like your own self-hosted backend. To do so, you'll need to do both of the following:

  • Modify your app client to send an App Check token along with each request to your backend, as described on this page.
  • Modify your backend to require a valid App Check token with every request, as described in Verify App Check tokens from a custom backend.

Before you begin

Add App Check to your app, using either the reCAPTCHA Enterprise provider or a custom provider.

Send App Check tokens with backend requests

In your app client, before each request, get a valid, unexpired, App Check token with appCheck().getToken(). The App Check library will refresh the token if necessary.

Once you have a valid token, send it along with the request to your backend. The specifics of how you accomplish this are up to you, but don't send App Check tokens as part of URLs, including in query parameters, as this makes them vulnerable to accidental leakage and interception. The following example sends the token in a custom HTTP header, which is the recommended approach.

Web

import { initializeAppCheck, getToken } from 'firebase/app-check';

const appCheck = initializeAppCheck(
    app,
    { provider: provider } // ReCaptchaV3Provider or CustomProvider
);

const callApiWithAppCheckExample = async () => {
  let appCheckTokenResponse;
  try {
      appCheckTokenResponse = await getToken(appCheck, /* forceRefresh= */ false);
  } catch (err) {
      // Handle any errors if the token was not retrieved.
      return;
  }

  // Include the App Check token with requests to your server.
  const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', {
      headers: {
          'X-Firebase-AppCheck': appCheckTokenResponse.token,
      }
  });

  // Handle response from your backend.
};

Web

const callApiWithAppCheckExample = async () => {
  let appCheckTokenResponse;
  try {
      appCheckTokenResponse = await firebase.appCheck().getToken(/* forceRefresh= */ false);
  } catch (err) {
      // Handle any errors if the token was not retrieved.
      return;
  }

  // Include the App Check token with requests to your server.
  const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', {
      headers: {
          'X-Firebase-AppCheck': appCheckTokenResponse.token,
      }
  });

  // Handle response from your backend.
};

Replay protection (beta)

When making a request to an endpoint for which you've enabled replay protection, acquire a token using getLimitedUseToken() instead of getToken():

import { getLimitedUseToken } from "firebase/app-check";

// ...

appCheckTokenResponse = await getLimitedUseToken(appCheck);