Flutter - Firebase App Check

Hasan Karlı
6 min readMar 1, 2024

--

Image source: Protecting Apps and APIs: A Deep Dive into Firebase App Check and Play Integrity at Chingari

App check service enhances the security of your application. The service helps prevent malicious resource usage in Firebase services, Google Cloud services, or your custom backend resource.

You can visit https://firebase.google.com/docs/app-check for more information.

The packages we use in this article

dependencies:
dio: ^5.4.1
firebase_app_check: ^0.2.1+14
firebase_core: ^2.25.4

After adding our packages to our application, we create a new Firebase project and include the Android and iOS projects in our application. After including them, we modify the main.dart file in our application as follows.

import 'package:example_app_check/firebase_options.dart';
import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await FirebaseAppCheck.instance.activate(
appleProvider: AppleProvider.debug,
androidProvider: AndroidProvider.debug);

runApp(const MyApp());
}

We run our application in the iOS environment, you will see a debug token generated for debug mode in the console.

Firebase App Check Debug Token: 2C394DBB-9724-4B70-8207-7CF878E520EE

Running in the Android environment, it will appear like this.

D/com.google.firebase.appcheck.debug.internal.DebugAppCheckProvider(14914): 
Enter this debug secret into the allow list in the
Firebase Console for your project: 88750bd0-854c-454c-96b5-920d3ea0b639

We want to generate token via Firebase App Check, we can call the getToken method.

String? token = await FirebaseAppCheck.instance.getToken();

When we call the method, the application will give the following error.

FirebaseException ([firebase_app_check/unknown] com.google.firebase.FirebaseException: Error returned from API. code: 403 body: App attestation failed.)

The reason for this error is that it is being called by a device that has not been verified by Firebase App Check. Therefore, we need to add the debug tokens generated for both Android and iOS from above to the Firebase console.

You can add the generated debug tokens for iOS and Android by clicking on “Manage debug tokens” located at the three dots in the App Check section of the Firebase console

After adding the debug tokens, you can log the token by calling the getToken method and viewing it in the console.

log('Token: $token');

In the log, we can see the generated token as follows.

Token:eyJraWQiOiJYcEhKU0EiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N…

Let’s look at how to generate tokens for the production environment after generating tokens in the debug environment.

For the Android environment, we have two providers available:

1-) SafetyNet
2-) Play Integrity

SafetyNet is a deprecated provider and will be fully deprecated after June 2024.

Therefore, we will use the Play Integrity provider for development in our application.

Including Play Integrity Provider in Our Application

First, open the Firebase console and navigate to the app check section. Click on “Play Integrity” under the Android section.

Here, it asks for the SHA-256 certificate fingerprint.

For this, you can either obtain the SHA-256 certificate fingerprint from an existing application on the Google Play Console or create a new application and copy the SHA-256 certificate fingerprint to add it to the Firebase Console.

After adding it to the Firebase Console, we have successfully activated the Play Integrity provider.

For the iOS environment, we have two providers available:

1-) Device Check
2-) App Attest

We can use both providers in the application. The preferred provider by Firebase is the App Attest, which is only valid for iOS 14.0 and above. Therefore, for devices that do not support App Attest, we will use the DeviceCheck provider.

Including Device Check and App Attest Providers in Our Application

When we click on Device Check in the Firebase App Check section, we need to enter the Auth key, Key ID, and Team ID information

To generate an Auth Key, you need a developer Apple account. If you have an account, you can go to the https://developer.apple.com/account/resources/authkeys/list page and create an Auth Key.

After clicking “Create a key,” you can enter any Key Name. Then, enable the Device Check option, proceed by clicking the “Continue” button, and finally, generate the Auth Key by clicking the “Register” button

After generating the Auth Key, you can download it only once. Therefore, store this key in a secure location for your own benefit.

After downloading the Auth Key, you should copy the Key ID and Team ID (located next to your developer account) from the downloaded page. Then, you can add them along with the Auth Key to the Device Check section in the Firebase Console.

After adding them, we have successfully activated the Device Check and App Attest providers.

After activating the providers on the Firebase Console, we need to configure App Attest in Xcode.

Here are the required steps:

1- Open our application in Xcode.
2- Click on the (+ Capability) button and add App Attest.

After adding it, when we restart our application

await FirebaseAppCheck.instance.activate(
appleProvider: AppleProvider.deviceCheck,
androidProvider:
kDebugMode ? AndroidProvider.debug : AndroidProvider.playIntegrity);

When we set the appleProvider to Device Check, you will see in the logs that tokens are successfully generated.

3- To make the App Attest provider work, we need to set the App Attest Environment in the .entitlements file to “production.”

After setting it, when we set the appleProvider to App Attest, tokens will be successfully generated.

await FirebaseAppCheck.instance.activate(
appleProvider: kDebugMode
? AppleProvider.debug
: AppleProvider.appAttestWithDeviceCheckFallback,
androidProvider:
kDebugMode ? AndroidProvider.debug : AndroidProvider.playIntegrity);

An Example Scenario

To protect the custom backend resource used in our application from malicious sources, we can implement the following scenario:

To ensure that each request to the custom backend is made by our application, we need to provide the generated token in the header of each request. For this purpose, we will write an interceptor using the Dio package. We will automatically add the token to the header of each request.

class AppCheckInterceptor extends Interceptor {
@override
Future<void> onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
String? appCheckToken = await FirebaseAppCheck.instance.getToken();

options.headers['X-Firebase-AppCheck'] = appCheckToken;

return handler.next(options);
}
}

The custom backend will enhance application security by verifying whether each incoming request’s header indicates that it originated from the Firebase application

Note: To determine whether the app check feature of your Android application is working in the production environment, you need to download the application from the Google Play Store. If you haven’t published the application yet, you can test it using Internal Test.

Thank you for reading, I hope it is helpful. If you have any questions, feel free to ask on LinkedIn.

You can access the source code of the application from the link below.

--

--