Search code examples
flutterfirebasegoogle-cloud-platformgoogle-cloud-storage

Flutter Firebase Upload with Authentication


I am trying to upload a profile photo as a logged in user with the following however I get error

E/flutter (32619): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: [firebase_storage/unauthorized] User is not authorized to perform the desired action.

My code

 User? user = await authenticationService.getCurrentUser();

    // Create a Reference to the file
    Reference ref =
        FirebaseStorage.instance.ref().child(user!.uid).child('/profile.jpg');

    final metadata = SettableMetadata(
        contentType: 'image/jpeg',
        customMetadata: {'picked-file-path': s!.path});

    UploadTask uploadTask = ref.putFile(File(s.path), metadata);

    var result = await uploadTask;
    print(result);

My rule

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read;
      allow write: if request.auth.uid == userId
                   && request.resource.contentType.matches('image/.+');
    }
  }
}

What am I missing here ?


Solution

  • I understand that you want to upload a file to the following reference

    FirebaseStorage.instance.ref().child(user!.uid).child('/profile.jpg');
    

    and check, in the security rules, that the id of the user executing the upload corresponds to the value of user!.uid.

    In your security rules, you have a check as request.auth.uid == userId but nowhere in the rules you define what is userId. You need to use a wildcard, as follows:

    service firebase.storage {
      // The {bucket} wildcard indicates we match files in all Cloud Storage buckets
      match /b/{bucket}/o {
        
        match /{userId}/{imageId} {
          allow read;
          allow write: if request.auth.uid == userId
                       && request.resource.contentType.matches('image/.+');
        }
      }
    }
    

    If you only upload images named profile.jpg in this "folder", you could add a check like imageId == 'profile.jpg' but you could also define the path as:

        match /{userId}/profile.jpg {
          allow read;
          allow write: if request.auth.uid == userId
                       && request.resource.contentType.matches('image/.+');
        }