Skip to content

feat(app-check): Debug token support for the activate method #16942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions docs/app-check/debug-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ To use the debug provider while running your app in a simulator interactively
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseAppCheck.instance.activate(
// Set appleProvider to `AppleProvider.debug`
appleProvider: AppleProvider.debug,
// Set providerApple to use AppleDebugProvider
providerApple: AppleDebugProvider('123a4567-b89c-12d3-e456-789012345678'),
);
runApp(App());
}
Expand Down Expand Up @@ -83,9 +83,9 @@ Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseAppCheck.instance.activate(
webRecaptchaSiteKey: 'recaptcha-v3-site-key',
// Set androidProvider to `AndroidProvider.debug`
androidProvider: AndroidProvider.debug,
webProvider: ReCaptchaV3Provider('recaptcha-v3-site-key'),
// Set providerAndroid to use AndroidDebugProvider
providerAndroid: AndroidDebugProvider('123a4567-b89c-12d3-e456-789012345678'),
);
runApp(App());
}
Expand Down Expand Up @@ -146,3 +146,44 @@ Because this token allows access to your Firebase resources without a
valid device, it is crucial that you keep it private. Don't commit it to a
public repository, and if a registered token is ever compromised, revoke it
immediately in the Firebase console.

## Manually setting up the App Check Debug Token for CI environment or development

If you want to use the debug provider in a testing environment or CI, you can
manually set the debug token in your app. This is useful when you want to run
your app in an environment where the debug token is not automatically generated.

To manually set the debug token, pass your debug token directly to the debug provider
classes when activating App Check. For example:

```dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';

// Import the firebase_app_check plugin
import 'package:firebase_app_check/firebase_app_check.dart';

Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseAppCheck.instance.activate(
webProvider: ReCaptchaV3Provider('recaptcha-v3-site-key'),
// Set providerAndroid with debug token
providerAndroid: AndroidDebugProvider('123a4567-b89c-12d3-e456-789012345678'),
// Set providerApple with debug token
providerApple: AppleDebugProvider('123a4567-b89c-12d3-e456-789012345678'),
);
runApp(App());
}

```

{# Google-internal common file: #}
<<../_includes/manage-debug-tokens.md>>

After you register the token, Firebase backend services will accept it as valid.

Because this token allows access to your Firebase resources without a
valid device, it is crucial that you keep it private. Don't commit it to a
public repository, and if a registered token is ever compromised, revoke it
immediately in the Firebase console.
24 changes: 12 additions & 12 deletions docs/app-check/default-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,19 @@ Future<void> main() async {
// You can also use a `ReCaptchaEnterpriseProvider` provider instance as an
// argument for `webProvider`
webProvider: ReCaptchaV3Provider('recaptcha-v3-site-key'),
// Default provider for Android is the Play Integrity provider. You can use the "AndroidProvider" enum to choose
// Default provider for Android is the Play Integrity provider. You can use the "providerAndroid" parameter to choose
// your preferred provider. Choose from:
// 1. Debug provider
// 2. Safety Net provider
// 3. Play Integrity provider
androidProvider: AndroidProvider.debug,
// Default provider for iOS/macOS is the Device Check provider. You can use the "AppleProvider" enum to choose
// your preferred provider. Choose from:
// 1. Debug provider
// 2. Device Check provider
// 3. App Attest provider
// 4. App Attest provider with fallback to Device Check provider (App Attest provider is only available on iOS 14.0+, macOS 14.0+)
appleProvider: AppleProvider.appAttest,
// 1. AndroidDebugProvider for debug environments
// 2. AndroidSafetyNetProvider (will be deprecated in the future)
// 3. AndroidPlayIntegrityProvider
providerAndroid: AndroidDebugProvider(),
// Default provider for iOS/macOS is the Device Check provider. You can use the "providerApple" parameter to choose
// your preferred provider. Choose from:
// 1. AppleDebugProvider for debug environments
// 2. AppleDeviceCheckProvider
// 3. AppleAppAttestProvider
// 4. AppleAppAttestProviderWithDeviceCheckFallback (App Attest provider is only available on iOS 14.0+, macOS 14.0+)
providerApple: AppleAppAttestProvider(),
);
runApp(App());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ private Task<Void> activate(Map<String, Object> arguments) {
case debugProvider:
{
FirebaseAppCheck firebaseAppCheck = getAppCheck(arguments);
FlutterFirebaseAppRegistrar.debugToken =
(String) arguments.get("androidDebugToken");
firebaseAppCheck.installAppCheckProviderFactory(
DebugAppCheckProviderFactory.getInstance());
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,38 @@
package io.flutter.plugins.firebase.appcheck;

import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import com.google.firebase.appcheck.debug.InternalDebugSecretProvider;
import com.google.firebase.components.Component;
import com.google.firebase.components.ComponentRegistrar;
import com.google.firebase.platforminfo.LibraryVersionComponent;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;

@Keep
public class FlutterFirebaseAppRegistrar implements ComponentRegistrar {
public class FlutterFirebaseAppRegistrar
implements ComponentRegistrar, InternalDebugSecretProvider {

private static final String DEBUG_SECRET_NAME = "fire-app-check-debug-secret";
public static String debugToken;

@Override
public List<Component<?>> getComponents() {
return Collections.<Component<?>>singletonList(
LibraryVersionComponent.create(BuildConfig.LIBRARY_NAME, BuildConfig.LIBRARY_VERSION));
Component<?> library =
LibraryVersionComponent.create(BuildConfig.LIBRARY_NAME, BuildConfig.LIBRARY_VERSION);

Component<InternalDebugSecretProvider> debugSecretProvider =
Component.builder(InternalDebugSecretProvider.class)
.name(DEBUG_SECRET_NAME)
.factory(container -> this)
.build();

return Arrays.asList(library, debugSecretProvider);
}

@Nullable
@Override
public String getDebugSecret() {
return debugToken;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

import 'firebase_options.dart';

Expand All @@ -26,6 +26,8 @@ Future<void> main() async {
androidProvider: AndroidProvider.debug,
appleProvider: AppleProvider.debug,
webProvider: ReCaptchaV3Provider(kWebRecaptchaSiteKey),
providerAndroid: const AndroidDebugProvider(debugToken: 'androidDebug'),
providerApple: const AppleDebugProvider(debugToken: 'appleDebug'),
);

runApp(MyApp());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@ - (id)initWithApp:app {
return self;
}

- (void)configure:(FIRApp *)app providerName:(NSString *)providerName {
- (void)configure:(FIRApp *)app
providerName:(NSString *)providerName
debugToken:(NSString *)debugToken {
if ([providerName isEqualToString:@"debug"]) {
if (debugToken != nil) {
// We have a debug token, so just need to stuff it in the environment and it will hook up
char *key = "FIRAAppCheckDebugToken", *value = (char *)[debugToken UTF8String];
int overwrite = 1;
setenv(key, value, overwrite);
}
FIRAppCheckDebugProvider *provider = [[FIRAppCheckDebugProvider alloc] initWithApp:app];
NSLog(@"Firebase App Check Debug Token: %@", [provider localDebugToken]);
if (debugToken == nil) NSLog(@"Firebase App Check Debug Token: %@", [provider localDebugToken]);
self.delegateProvider = provider;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ @implementation FLTAppCheckProviderFactory
self.providers[app.name] = [FLTAppCheckProvider new];
FLTAppCheckProvider *provider = self.providers[app.name];
// We set "deviceCheck" as this is currently what is default. Backward compatible.
[provider configure:app providerName:@"deviceCheck"];
[provider configure:app providerName:@"deviceCheck" debugToken:nil];
}

return self.providers[app.name];
}

- (void)configure:(FIRApp *)app providerName:(NSString *)providerName {
- (void)configure:(FIRApp *)app
providerName:(NSString *)providerName
debugToken:(NSString *)debugToken {
if (self.providers == nil) {
self.providers = [NSMutableDictionary new];
}
Expand All @@ -41,7 +43,7 @@ - (void)configure:(FIRApp *)app providerName:(NSString *)providerName {
}

FLTAppCheckProvider *provider = self.providers[app.name];
[provider configure:app providerName:providerName];
[provider configure:app providerName:providerName debugToken:debugToken];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)flutter
- (void)activate:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result {
NSString *appNameDart = arguments[@"appName"];
NSString *providerName = arguments[@"appleProvider"];
NSString *debugToken = arguments[@"appleDebugToken"];

FIRApp *app = [FLTFirebasePlugin firebaseAppNamed:appNameDart];
[self->providerFactory configure:app providerName:providerName];
[self->providerFactory configure:app providerName:providerName debugToken:debugToken];
result.success(nil);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

@property id<FIRAppCheckProvider> delegateProvider;

- (void)configure:(FIRApp *)app providerName:(NSString *)providerName;
- (void)configure:(FIRApp *)app
providerName:(NSString *)providerName
debugToken:(NSString *)debugToken;

- (id)initWithApp:(FIRApp *)app;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

@property NSMutableDictionary *_Nullable providers;

- (void)configure:(FIRApp *_Nonnull)app providerName:(NSString *_Nonnull)providerName;
- (void)configure:(FIRApp *_Nonnull)app
providerName:(NSString *_Nonnull)providerName
debugToken:(NSString *_Nullable)debugToken;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ import 'package:firebase_core_platform_interface/firebase_core_platform_interfac
export 'package:firebase_app_check_platform_interface/firebase_app_check_platform_interface.dart'
show
AndroidProvider,
AndroidAppCheckProvider,
AndroidDebugProvider,
AndroidPlayIntegrityProvider,
AndroidSafetyNetProvider,
AppleProvider,
AppleAppCheckProvider,
AppleDebugProvider,
AppleDeviceCheckProvider,
AppleAppAttestWithDeviceCheckFallbackProvider,
ReCaptchaEnterpriseProvider,
ReCaptchaV3Provider;
export 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,42 @@ class FirebaseAppCheck extends FirebasePluginPlatform {

/// Activates the Firebase App Check service.
///
/// On web, provide the reCAPTCHA v3 Site Key which can be found in the
/// Firebase Console.
/// ## Platform Configuration
///
/// On Android, the default provider is "play integrity". If you wish to set the provider to "safety net" or "debug", you may set the `androidProvider` property using the `AndroidProvider` enum
/// **Web**: Provide the reCAPTCHA v3 Site Key using `webProvider`, which can be
/// found in the Firebase Console.
///
/// On iOS or macOS, the default provider is "device check". If you wish to set the provider to "app attest", "debug" or "app attest with fallback to device check"
/// ("app attest" is only available on iOS 14.0+, macOS 14.0+), you may set the `appleProvider` property using the `AppleProvider` enum
/// **Android**: The default provider is "play integrity". Use `providerAndroid`
/// to configure alternative providers such as "safety net", debug providers, or
/// custom implementations via `AndroidAppCheckProvider`.
///
/// **iOS/macOS**: The default provider is "device check". Use `providerApple`
/// to configure alternative providers such as "app attest", debug providers, or
/// "app attest with fallback to device check" via `AppleAppCheckProvider`.
/// Note: App Attest is only available on iOS 14.0+ and macOS 14.0+.
///
/// ## Migration Notice
///
/// The `androidProvider` and `appleProvider` parameters will be deprecated
/// in a future release. Use `providerAndroid` and `providerApple` instead,
/// which support the new provider classes including `AndroidDebugProvider`
/// and `AppleDebugProvider` for passing debug tokens directly.
///
/// For more information, see [the Firebase Documentation](https://firebase.google.com/docs/app-check)
Future<void> activate({
WebProvider? webProvider,
AndroidProvider androidProvider = AndroidProvider.playIntegrity,
AppleProvider appleProvider = AppleProvider.deviceCheck,
AndroidAppCheckProvider providerAndroid =
const AndroidPlayIntegrityProvider(),
AppleAppCheckProvider providerApple = const AppleDeviceCheckProvider(),
}) {
return _delegate.activate(
webProvider: webProvider,
androidProvider: androidProvider,
appleProvider: appleProvider,
providerAndroid: providerAndroid,
providerApple: providerApple,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

import 'dart:async';

import 'package:flutter_test/flutter_test.dart';
import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_test/flutter_test.dart';

import './mock.dart';

void main() {
Expand Down Expand Up @@ -57,6 +58,12 @@ void main() {
test('successful call', () async {
await appCheck.activate(
webProvider: ReCaptchaV3Provider('key'),
providerAndroid: const AndroidDebugProvider(
debugToken: 'androidDebug',
),
providerApple: const AppleDebugProvider(
debugToken: 'appleDebug',
),
);

expect(
Expand All @@ -66,8 +73,10 @@ void main() {
'FirebaseAppCheck#activate',
arguments: <String, dynamic>{
'appName': defaultFirebaseAppName,
'androidProvider': 'playIntegrity',
'appleProvider': 'deviceCheck',
'androidProvider': 'debug',
'appleProvider': 'debug',
'androidDebugToken': 'androidDebug',
'appleDebugToken': 'appleDebug',
},
),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

export 'src/method_channel/method_channel_firebase_app_check.dart';
export 'src/platform_interface/platform_interface_firebase_app_check.dart';
export 'src/android_provider.dart';
export 'src/android_providers.dart';
export 'src/apple_provider.dart';
export 'src/apple_providers.dart';
export 'src/method_channel/method_channel_firebase_app_check.dart';
export 'src/platform_interface/platform_interface_firebase_app_check.dart';
export 'src/web_providers.dart';
Loading