I am developing a Flutter application that reads from a Firestore database and Firebase Storage. The Firebase Storage read rules are set to allow only authenticated users. I also have a Python script that uploads content to Firebase Storage and updates Firestore with the relevant file URLs.
Here is the uploading snippet
def _upload_file(self, file_path: str, storage_path: str) -> str:
blob = self.bucket.blob(storage_path)
blob.upload_from_filename(file_path)
return blob.public_url
however the urls generated by that result in a 403 (even by the authenticated user of the application and also if the rules of the storage are set to always read and write).
Problem: I need to generate URLs for the uploaded files that can be stored in Firestore and accessed by the Flutter application. Here are the approaches I have tried and their issues:
blob.public_url
as said before, results in a 403 error in Flutter even if the user is authenticated.
generate_signed_url()
Not suitable as it expires after 7 days.
blob.make_public()
Works in Flutter but bypasses security rules, posing a security risk (it makes the url work from everywhere even if the rules are set to allow read only from authenticated users).
Additional Info In a previous flutter application I developed, I had to do the upload of the content from the app itself and the code in dart was working fine generating the correct url
Future<String> uploadUserImage(File image, String uid) async {
final String fileName = uid + ".jpg";
final ref =
_storage.ref().child(StorageCollections.userImages).child(fileName);
await ref.putFile(image);
return await ref.getDownloadURL();
}
// generates this url: https://firebasestorage.googleapis.com/v0/b/xxxxx/o/userImages%xxxxx.jpg?alt=media&token=xxxxxx
However i can't seem to achieve the same result in Python.
Question
How can I get, after the upload of a file, a correct url that works with Storage rules and doesn't expire with the module firebase_admin (or other ways)?
If you want to be able to set security rules to control access to the data, you should not be using a download URL or signed URL, as both of those bypass the security rules.
Instead, write either the gs://
URL or the relative path of the image to the database, create a reference based on that in your client-side code (potentially using refFromURL
), and then use the SDK methods to download the data to memory or a local file.