app_check_secure 0.0.1 copy "app_check_secure: ^0.0.1" to clipboard
app_check_secure: ^0.0.1 copied to clipboard

A simple, production-ready Flutter package that completely abstracts Firebase App Check for Android, iOS, and Web.

app_check_secure #

A simple, production-ready Flutter package that completely abstracts Firebase App Check.

Your application never talks to Firebase App Check directly — it only uses AppCheckSecure.

Supported platforms: Android · iOS · Web


Features #

  • Single public API: AppCheckSecure
  • Opt-in platforms: enableAndroid / enableIos / enableWeb (default false)
  • Automatic provider selection via debug (optional overrides)
  • Debug token helpers for Android, iOS, and Web (config or setters)
  • Android providers: Debug, Play Integrity
  • iOS providers: Debug, DeviceCheck, App Attest, App Attest + DeviceCheck fallback
  • Web providers: Debug, reCAPTCHA v3, reCAPTCHA Enterprise
  • Token cache, refresh, clear, and change stream
  • Optional logging with [AppCheck] prefix
  • Package-owned exceptions (Firebase errors are never exposed)
  • Retry with configurable count and delay

Installation #

1. Add the package #

dependencies:
  app_check_secure: ^0.0.1
  firebase_core: ^4.0.0

Then run:

flutter pub get

firebase_app_check is pulled in transitively by this package. Your app still needs firebase_core to initialize Firebase.

2. Configure Firebase for your app #

Follow the official FlutterFire setup:

Ensure google-services.json (Android), GoogleService-Info.plist (iOS), and web Firebase options are in place.


Firebase setup #

  1. Open the Firebase Console.
  2. Select your project → Build / SecurityApp Check.
  3. Register each app (Android, iOS, Web) with the appropriate provider.
  4. Start in Monitoring mode, then enable Enforcement for Storage, Firestore, Functions, etc. when ready.
  5. For local development, register debug tokens under App Check → Manage debug tokens.

Android setup #

Play Integrity (production) #

  1. In Firebase Console → App Check, register your Android app with Play Integrity.
  2. Add your app’s SHA-256 certificate fingerprints in Project Settings.
  3. Use production mode (debug: false) — the package selects Play Integrity automatically:
debug: false,
enableAndroid: true,

Debug (development / CI) #

  1. Use debug: true (package selects the Android debug provider).
  2. Either:
    • Run once and copy the token from Logcat, or
    • Pass a known token via androidDebugToken / AppCheckSecure.setAndroidDebugToken.
  3. Register that token in Firebase Console → App Check → Manage debug tokens.
debug: true,
enableAndroid: true,
androidDebugToken: 'YOUR_REGISTERED_DEBUG_TOKEN', // optional
enableLogging: true,

SafetyNet (legacy) #

AndroidProviderType.safetyNet may be passed as an optional override, but SafetyNet is no longer supported by the FlutterFire App Check SDK. Prefer Play Integrity. Selecting SafetyNet throws a ConfigurationException.


iOS setup #

DeviceCheck / App Attest #

  1. In Firebase Console → App Check, register your iOS app with DeviceCheck or App Attest.
  2. Enable App Attest capability in Xcode when using App Attest (iOS 14+).
  3. Ensure your Apple Developer team and App ID are correctly configured.
  4. With debug: false, the package defaults to App Attest with DeviceCheck fallback. Override with appleProvider if needed.
debug: false,
enableIos: true,
// optional: appleProvider: AppleProviderType.deviceCheck,

Debug (development / CI) #

  1. Use debug: true (package selects the Apple debug provider).
  2. Either copy the token from Xcode / device logs, or pass iosDebugToken / AppCheckSecure.setIosDebugToken.
  3. Register it in Firebase Console → Manage debug tokens.
debug: true,
enableIos: true,
iosDebugToken: 'YOUR_REGISTERED_DEBUG_TOKEN', // optional
enableLogging: true,

Web setup #

Production (reCAPTCHA) #

  1. In Firebase Console → App Check, register your web app with reCAPTCHA v3 or reCAPTCHA Enterprise.
  2. Copy the site key.
  3. Pass it via webSiteKey (required on web when not using the debug provider).
enableWeb: true,
debug: false,
webProvider: WebProviderType.recaptchaV3, // optional; this is the default
webSiteKey: 'YOUR_RECAPTCHA_SITE_KEY',

Or:

enableWeb: true,
webProvider: WebProviderType.recaptchaEnterprise,
webSiteKey: 'YOUR_RECAPTCHA_ENTERPRISE_SITE_KEY',

Do not hardcode production keys in source control when avoidable — use --dart-define or your secrets pipeline.

Debug (development / CI) #

  1. Use debug: true (package selects the Web debug provider; webSiteKey not required).
  2. Pass webDebugToken / AppCheckSecure.setWebDebugToken, or let the SDK print one in the browser console.
  3. Register the token in Firebase Console → Manage debug tokens.
enableWeb: true,
debug: true,
webDebugToken: 'YOUR_REGISTERED_DEBUG_TOKEN', // optional
enableLogging: true,

Usage #

Import only the package entry point:

import 'package:app_check_secure/app_check_secure.dart';

Initialize (after Firebase) #

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  // Optional: set debug tokens before initialize (CI / known devices).
  // AppCheckSecure.setAndroidDebugToken('...');
  // AppCheckSecure.setIosDebugToken('...');
  // AppCheckSecure.setWebDebugToken('...');

  await AppCheckSecure.initialize(
    config: AppCheckConfig(
      debug: kDebugMode,
      // Opt-in: only enable platforms you need (defaults are false).
      enableAndroid: true,
      enableIos: true,
      enableWeb: true,
      webSiteKey: const String.fromEnvironment('RECAPTCHA_SITE_KEY'),
      enableLogging: true,
      autoRefresh: true,
    ),
  );

  runApp(const MyApp());
}

The package detects the current device platform, checks the matching enable* flag, and selects providers from debug (unless you pass an override).

Debug tokens #

// Before initialize (optional)
AppCheckSecure.setAndroidDebugToken('...');
AppCheckSecure.setIosDebugToken('...');
AppCheckSecure.setWebDebugToken('...');

print(AppCheckSecure.getAndroidDebugToken());
print(AppCheckSecure.getIosDebugToken());
print(AppCheckSecure.getWebDebugToken());
print(AppCheckSecure.getDebugToken()); // current platform

AppCheckSecure.clearDebugTokens();

Or pass them in config: androidDebugToken / iosDebugToken / webDebugToken (config values win when both config and setters are used).

Get / refresh / clear App Check token #

final token = await AppCheckSecure.getToken();
final fresh = await AppCheckSecure.refreshToken();
await AppCheckSecure.clearToken();

print(AppCheckSecure.currentToken);
print(AppCheckSecure.isInitialized);

Listen for token changes #

AppCheckSecure.onTokenChanged.listen((token) {
  // Handle updated or cleared token
});

Dispose #

await AppCheckSecure.dispose();

Configuration #

Field Type Default Description
debug bool false Use debug providers (unless overridden)
enableAndroid bool false Allow App Check when running on Android
enableIos bool false Allow App Check when running on iOS
enableWeb bool false Allow App Check when running on Web
webSiteKey String? null Required on web for reCAPTCHA (not needed for debug)
webProvider WebProviderType recaptchaV3 Web attestation provider (ignored when debug: true)
androidProvider AndroidProviderType? null Optional Android override
appleProvider AppleProviderType? null Optional iOS override
androidDebugToken String? null Optional Android debug token
iosDebugToken String? null Optional iOS debug token
webDebugToken String? null Optional Web debug token
enableLogging bool false Enables [AppCheck] logs
autoRefresh bool true Firebase automatic token refresh
forceRefresh bool false Default for getToken() when forceRefresh is omitted
retryCount int 3 Extra retries after the first failure (0 = one attempt)
retryDelay Duration 2s Delay between retries

Automatic provider selection #

debug Android (default) iOS (default) Web (default)
true Debug Debug Debug
false Play Integrity App Attest + DeviceCheck fallback reCAPTCHA (webProvider)

Provider override enums #

Android: debug · playIntegrity · safetyNet (unsupported — throws)

Apple: debug · deviceCheck · appAttest · appAttestWithDeviceCheckFallback

Web: debug · recaptchaV3 · recaptchaEnterprise


Examples #

Production config #

const config = AppCheckConfig(
  debug: false,
  enableAndroid: true,
  enableIos: true,
  enableWeb: true,
  webSiteKey: String.fromEnvironment('RECAPTCHA_SITE_KEY'),
  enableLogging: false,
  autoRefresh: true,
);

Debug config #

const config = AppCheckConfig(
  debug: true,
  enableAndroid: true,
  enableIos: true,
  enableWeb: true,
  androidDebugToken: String.fromEnvironment('ANDROID_APP_CHECK_DEBUG_TOKEN'),
  iosDebugToken: String.fromEnvironment('IOS_APP_CHECK_DEBUG_TOKEN'),
  webDebugToken: String.fromEnvironment('WEB_APP_CHECK_DEBUG_TOKEN'),
  enableLogging: true,
);

Enable only some platforms #

final config = AppCheckConfig(
  debug: kDebugMode,
  enableAndroid: true,
  enableIos: true,
  // enableWeb defaults to false — throws if you run on web
);

Force a fresh token #

final token = await AppCheckSecure.getToken(forceRefresh: true);
// or
final token = await AppCheckSecure.refreshToken();

Error handling #

try {
  await AppCheckSecure.initialize(config: config);
  final token = await AppCheckSecure.getToken();
} on ConfigurationException catch (e) {
  // Invalid config (e.g. missing webSiteKey)
} on InitializationException catch (e) {
  // Not initialized or activation failed
} on TokenException catch (e) {
  // Token fetch / refresh failed
} on PlatformNotSupportedException catch (e) {
  // Not Android, iOS, or Web
} on AppCheckException catch (e) {
  // Any package error
}

See the example/ app for a full demonstration.


Public API #

API Description
AppCheckSecure.initialize(config:) Activate App Check
AppCheckSecure.getToken({forceRefresh}) Get token (cached unless forced)
AppCheckSecure.refreshToken() Force refresh
AppCheckSecure.clearToken() Clear cache
AppCheckSecure.currentToken Last cached token
AppCheckSecure.isInitialized Initialization flag
AppCheckSecure.onTokenChanged Token change stream
AppCheckSecure.setAndroidDebugToken Set Android debug token (before init)
AppCheckSecure.setIosDebugToken Set iOS debug token (before init)
AppCheckSecure.setWebDebugToken Set Web debug token (before init)
AppCheckSecure.getAndroidDebugToken Read Android debug token
AppCheckSecure.getIosDebugToken Read iOS debug token
AppCheckSecure.getWebDebugToken Read Web debug token
AppCheckSecure.getDebugToken Read debug token for current platform
AppCheckSecure.clearDebugTokens Clear setter-based debug tokens
AppCheckSecure.dispose() Tear down resources

Applications should not import or call firebase_app_check for day-to-day App Check usage when using this package.


Logging #

Enable with enableLogging: true:

[AppCheck] Initializing
[AppCheck] Android Provider : Play Integrity
[AppCheck] Initialization Completed
[AppCheck] Token Generated
[AppCheck] Token Refreshed

Troubleshooting #

InitializationException: AppCheckSecure is not initialized #

Call AppCheckSecure.initialize after Firebase.initializeApp() and before getToken / refreshToken.

ConfigurationException: webSiteKey is required #

On web, always provide a non-empty webSiteKey.

ConfigurationException about SafetyNet #

Use AndroidProviderType.playIntegrity instead. SafetyNet was removed from FlutterFire.

Token requests fail / 403 App attestation failed #

  • Confirm the correct provider is registered in Firebase Console.
  • For debug builds, register the debug token.
  • On Android, verify SHA-256 fingerprints.
  • On iOS, verify App Attest / DeviceCheck setup and provisioning.
  • Prefer Monitoring mode until tokens succeed consistently.

Already initialized warning #

initialize is idempotent after the first success. Call dispose() if you need to re-initialize with a different config (e.g. tests).

Hot restart #

Call dispose() then initialize() again if state looks stale after hot restart.


FAQ #

Why not call Firebase App Check directly?
This package keeps provider selection, retries, caching, logging, and error mapping in one place so every app shares the same behavior.

Does this initialize Firebase?
No. Your app must call Firebase.initializeApp() first.

Is SafetyNet supported?
No longer by FlutterFire. The enum value remains and fails fast with a clear ConfigurationException.

Can I use this with multiple Firebase apps?
This package uses the default Firebase app (FirebaseAppCheck.instance). Multi-app support is out of scope by design.

Does clearToken deactivate App Check?
No. It only clears the in-memory cache. Use dispose() to tear down listeners and reset the service.

Is macOS / Windows / Linux supported?
No. Only Android, iOS, and Web. Other platforms throw PlatformNotSupportedException.


License #

See LICENSE.

0
likes
160
points
38
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A simple, production-ready Flutter package that completely abstracts Firebase App Check for Android, iOS, and Web.

Repository (GitHub)
View/report issues

Topics

#firebase #app-check #security #flutter

License

MIT (license)

Dependencies

firebase_app_check, flutter

More

Packages that depend on app_check_secure