Wednesday 10 May 2023

Implement Flutter App Check Breaking Firebase storage on Android

The Firebase storage is keep throwing auth issue. Even when I am able to successfully get the user information from firebase auth instance

By using

Miscellaneous.logMessage(
      Tag, "currentUser ${FirebaseAuth.instance.currentUser}");

App Check setup in the current application

-Added Dependency in yaml file

  firebase_core: ^1.13.1
  firebase_analytics: ^8.3.4
  firebase_auth: ^3.3.11
  cloud_firestore: ^2.5.4
  firebase_crashlytics: ^2.5.3
  firebase_messaging: ^10.0.9
  firebase_database: ^7.2.2
  firebase_storage: ^10.2.9
  firebase_app_check: ^0.0.6+7

-And added this code in main.dart

Future<void> main() async {

    WidgetsFlutterBinding.ensureInitialized();
    
      await Firebase.initializeApp();
    
      await FirebaseAppCheck.instance.activate(
        webRecaptchaSiteKey: 'recaptcha-v3-site-key',
      );

}

-Setup in Android

Gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: ['*mock*.jar'])
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation("androidx.browser:browser:1.4.0")
    implementation platform('com.google.firebase:firebase-bom:28.2.1')
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'com.google.android.gms:play-services-auth:20.1.0'
    implementation 'com.google.android.gms:play-services-auth-api-phone:18.0.1'
    implementation 'com.google.firebase:firebase-appcheck-debug:16.0.0-beta04'
    implementation 'com.google.firebase:firebase-appcheck-safetynet:16.0.0-beta04'
    androidTestImplementation 'com.google.firebase:firebase-appcheck-debug-testing:16.0.0-beta04'
    implementation 'androidx.work:work-runtime-ktx:2.7.1'
    implementation 'com.google.android.play:core:1.10.3'
    implementation 'org.jetbrains:annotations:20.1.0'

}

MainActivity

public class MainActivity extends FlutterActivity {
    @Override
    protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FirebaseApp.initializeApp(this);
        FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance();
        firebaseAppCheck.installAppCheckProviderFactory(DebugAppCheckProviderFactory.getInstance());
    }
    

Error

StorageUtil(15655): Error getting App Check token; using placeholder token instead. Error: com.google.firebase.FirebaseException: Error returned from API. code: 403 body: App attestation failed. [+3151 ms]

W/StorageUtil(15655): Error getting App Check token; using placeholder token instead. Error: com.google.firebase.FirebaseException: Too many attempts.

Code for Storage upload

 firebaseStorageUtils.sendImageTOFirebase(imageFile, false).then((value) {
        Miscellaneous.logMessage(Tag, "sendImageTOFirebase URL $value");
        if (value == null) {
          Miscellaneous.showMessage(context, "Server Error!!,Retry Later");
          return;
        }
        setState(() {
          Miscellaneous.logMessage(Tag, "Download URL $value");
          profileUrl = value;
          Miscellaneous.logMessage(Tag, imageFile.path);
        });
      });

 Future<String?> sendImageTOFirebase(File imageSend, bool imgPost) async {
    var len = await imageSend.length();
    var fileSend;
    Miscellaneous.logMessage(Tag, len);
    if (len <= Constants.maxImageSize) {
      fileSend = await compressFile(imageSend, 70);
    } else {
      var quality;
      if (len >= Constants.maxImageSizeLarge) {
        quality = 30;
      } else {
        quality = 50;
      }
      fileSend = await compressFile(imageSend, quality);
    }

    Miscellaneous.showLoader(context, this);

    Miscellaneous.logMessage(Tag, fileSend.path);

    if (imgPost) {
      fileName = "${Miscellaneous.uniqueName()}.png";
      drivePath = 'post/$userUUID/$fileName';
    } else {
      drivePath = 'user_profile/$userUUID/defaultProfile.png';
    }

    Miscellaneous.logMessage(Tag, "drivePath$drivePath");

    try {
      FirebaseAuth auth = FirebaseAuth.instance;

      if (auth.currentUser != null) {
        Miscellaneous.logMessage(Tag, auth.currentUser.toString());
      }

      // Create your custom metadata.
      firebase_storage.SettableMetadata metadata =
          firebase_storage.SettableMetadata(
        cacheControl: 'max-age=60',
        customMetadata: <String, String>{
          'userId': userUUID,
        },
      );

      await Firebase.initializeApp();

      await firebase_storage.FirebaseStorage.instance
          .ref(drivePath)
          .putFile(fileSend, metadata);

      String downloadUrlImage = await firebase_storage.FirebaseStorage.instance
          .ref(drivePath)
          .getDownloadURL();

      this.downloadUrl = downloadUrlImage;
      Miscellaneous.logMessage(Tag, "downloadURL $downloadUrlImage");

      if (imgPost) {
        Miscellaneous.dismissLoader(context);
        return downloadUrlImage;
      } else {
        bool uploadToFirebaseImage = await uploadToFirebase(auth);
        Miscellaneous.dismissLoader(context);
        if (uploadToFirebaseImage) {
          return downloadUrlImage;
        } else {
          return null;
        }
      }
    } on firebase_core.FirebaseException catch (e) {
      // e.g, e.code == 'canceled'
      Miscellaneous.logMessage(Tag, "error $e");
      Miscellaneous.dismissLoader(context);
      return null;
    }
  }

Firebase Rules

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
  
  //if the file is less than 200kB
    match /user_profile {
      allow read, write: 
      if request.auth != null && request.resource.size <= 200 * 1024; 
    }
    
     match /user_profile/{userId}/defaultProfile.png {
           allow read: if request.auth.uid == userId;
             allow write: if request.auth.uid == userId;
        }
    
    match /post/{userId}/{fileName} {
           allow read;
             allow write: if request.auth.uid == userId &&  request.resource.size <= 200 * 1024;
       allow delete: if request.auth.uid == userId;

       
        }
    
  }
}

What's the correct way to use App Check in flutter?



from Implement Flutter App Check Breaking Firebase storage on Android

No comments:

Post a Comment