Firebase logic for implementing a profile image uploader on react-native - firebase

I have question regarding the logic for implementing a profile image uploader and storing the image url in a database under the user uploading the image using react-native and firebase authentication, cloud functions, database and storage services.
An example of the way the imageUrl would be stored
{
“users”: {
“7ad9310fsasghsa72”: {
imageUrl: ‘imageHoster.com’
},
“4k2dH5lifs35kfsp0”: {
imageUrl: ‘imageHoster.com’
},
}
}
The question is, is the logic below a correct utilisation of firebase services in relation to implementing this feature or is there a better way?
User uploads image on mobile device through react-native
Image gets sent to a firebase cloud function, for validating it, reducing it to 150x150
Image gets stored in google cloud storage
URL returned from the stored image is stored in firebase database under the user who is uploading the image
Also using this firebase implementation what is the way for authenticating the user making the request inside of the cloud function so that I’m able to store the url of the image returned from storage service under that user in the database?
Thanks

You can check out the following link for callable cloud functions
Call functions from your app
With callables, Firebase Authentication and FCM tokens, when available, are automatically included in requests.
Your can use the auth data inside the request parameter to keep track of whose data is contained in the request.
Storing the image url string inside the database is the way to go if you would like to keep track of the user's profile photo. It is also the recommended way of building your app.
Cheers,if you get stuck,the community here will help.
Happy coding!

Related

Reading firebase storage image security rules

I am using Firebase storage and firestore with flutter,
I came across two options to retrieve Firebase storage image
Setting Firebase storage image url in firestore database and then fetching it with network image
Getting image url from Firebase storage directly
I don't know much about tokens.
My security rules states that only auth users can read my Firebase storage but if I use first option my image url with token is stored in my firestore database using that url anyone can access my storage. I am not sure does Firebase refresh it's storage token automatically then if this is the case my app will experience crash.
Which is the most secure and long lasting way or please answer if any other secure way to fetch images
Firebase storage tokens won't expire unless you revoke them. The token may update if you overwrite the image i.e. update it. Now that's totally your call if you would like to make a separate request just to get the download URL or store the URL in realtime database when an image is uploaded and fetch it along with other data.
Security rules of Firebase Storage will prevent non-authenticated users from getting the download URL only. If an authenticated user shares the URL with anyone, they will be able to see the image as they have the URL with that random token now.
If the data you are fetching from realtime database requires the user to be logged in at first place, then I'd just store the URL in the database itself as I don't think it makes sense to make another request and have the same rules for Firebase storage. I don't know your exact use case so there may be exceptions for doing this.
If you don't need that image URL always then that might be waste of bandwidth, then you should consider making separate request to get the storage URLs.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
These rules will allow any authenticated user to request the URL. But as I mentioned earlier, anyone with this link can access the file.

Can I make firebase file URLs publicly available without requiring token?

I am using firebase to allow users to upload their files to the Storage buckets. I was using the getDownLoadURL() to fetch the publicly available URL...however, this comes with an embedded token to allow access to the file.
In my same app, I'm using the Google Document viewer which takes a URL to preview the doc. Unfortunately, the Google Doc Viewer does not work with the firebase URLs's with the embedded token.
In Google Console, on an individual file, I click to make it public. In that case, the URL is now reachable via the https://storage.googleapis.com// format...and I don't need to use the token which works great.
So, what I want to do is mark/make a file public when I'm uploading it to firebase. I have reviewed the firebase docs and there doesn't seem to be a makePublic() method like there is on the Google API's.
Is there a way I can mark a file as public during upload, so that it can be accessed without any token?
The other solution was that I could update the bucket to be accessible, but this makes it totally open to be browsed at https://storage.googleapis.com/, which I don't want to do.
The client-side Firebase APIs don't know anything about the underlying Google Cloud Platform configurations for public content in storage buckets. So that won't be an option.
You will have to involve some backend code to change the object's configuration after it's uploaded. You could set up your own API endpoint via Cloud Functions (or whatever backend you want) to run one of the Google Cloud Storage server SDKs to set the file as public. (You will probably also want some way to authorize that the user calling your API should be able to make this change.)

Flutter - Understanding Firebase Admin and how to get a user's information from email/uid/name

I'm making a little Snapchat clone, and a part of this app I'm trying to build is the ability to add a friend and start a conversation with them. I'm using Firebase to manage my users and I'm a little stuck now trying to figure out what works and why I'm getting problems trying to use some methods or functions.
What I want is this simple line of code to work:
var userByEmail = await _admin.app().auth().getUserByEmail("b#gmail.com");
print(userByEmail.toString());
However this has been giving my some problems, most recently, the following error message:
Unhandled Exception: FirebaseAuthError(auth/invalid-credential): Must initialize app with a cert credential or set your Firebase project ID as the GOOGLE_CLOUD_PROJECT environment variable to call verifyIdToken().
Getting to this point made me want to first ask a question about FirebaseAdmin and Auth before continuing and potentially screwing up my app settings.
Is there a simple way to do what I'm trying to do?
I have a Firebase.instance.initializeApp() in my Main function, do I only ever call that once or should I start initilizeApp in the initState of each Stateful Widget where needed?
What does this error message actually mean?
You are trying to use the Firebase Admin SDK in your Flutter code, which is not possible. The Admin SDKs give full administrative access to your Firebase project, which would be a serious security concern if you allow that in your Flutter app.
If you want to allow certain administrative functionality in your application, you will have to make that functionality available yourself. For example, to look up a user by their email address, there are two common approaches:
Store the minimal information about each user in a cloud-accessible database (such as Firebase's Realtime Database or Cloud Firestore) when each user registers with your app, and then look it up from there.
Wrap the getUserByEmail from the Admin SDK in a custom API that you make for yourself, on a server you control or in Cloud Functions. In that API you validate that the user making the call is authorized to do so, then call Firebase through the API you were trying to use, and return the minimal result back to the caller.
Both of these are feasible and can work to solve a variety of use-cases. But if you've never built backend code before, you might find the first approach easier to get started with.
Also see:
How to get Firebase UID knowing email user?
Flutter get User Data from Firebase
The right way to do what you want is using Firebase auth, authenticating your user and using a collection to store and retrieve users information. That auth information provided by firebase should only be used for authentication and security purposes.
The Firebase admin must have a user logged in to work properly, but its purpose is to provide a more administration environment and should not be used inside a clients app, unless its an admin app.
With all that said, lets go for the rescue:
Authenticate your user (using firebase auth);
After auth, save all the user information you want to share with other user inside its own collection (you will need to create one);
When an authenticated user (this is important) 'request any other users data, you query for the data in the previous created collection.

How to use firebase storage along with custom server?

I am planning to use firebase storage as storage bucket for images for my app.
Shall I use client side firebase SDK to upload images directly to firebase or, shall I send image to my server first and use firebase Admin-sdk and let the server upload image to firebase? Also I have other data along with image which client will send, that server needs to handle.
EDIT: I was confused about one thing, if I use firebase admin-sdk, first my image need to upload to the server and then server will send it to firebase storage, won't it double the upload time?
Both are valid options, and neither is pertinently better than the other.
I typically prefer using the Firebase SDK to upload to Cloud Storage, since it saves me from having to come up with my own client-side code and handling things like network detection, retries, etc. I then often write metadata about the file to the Firebase database (either the Realtime Database, or Cloud Firestore) and use that to trigger Cloud Functions to do any backend processing that is needed on the image.
But it's equally valid to write your own server-side endpoint that does the processing of the image, and post to that from within your app.

How can I generate a "Download URL" with a token using the management API, and is that what I want?

I am trying to build a Firebase admin utility that I can use to upload files to Firebase Storage and then return a long lived URL that I can store in the Firebase Realtime DB to access this file.
I believe I can do this in the Firebase Console by going to my project's console, clicking Storage on the left, clicking Upload File. Once the file is uploaded, I can get a URL by selecting the file in the list to open the right information pane, and then expanding the File Location section.
In that section there is a Download URL which appears to be a long lived but revocable URL containing a token of some type. Is this URL safe to store in a DB for long term storage? It does appear to be the same URL that is returned from the file upload api, which another Google Codelab (for Flutter) showed being stored in the realtime database.
However, I cannot figure out how to generate that type of URL from the Firebase Storage Management API. I am using NodeJS, but it should apply to all versions of the API AFAIK. I can only find a getSignedUrl call which does not seem to return the same URL, and appears to be time limited and containing a link to the service account...not what I want to store in a database.
let bucket = admin.storage().bucket();
bucket.upload('innovation3.jpeg', {destination: 'image_assets/innovation3.jpeg'},
function(err, file) {
file.getSignedUrl({action: 'read'},
function(err, url) {
console.log('Url: ' + url);
})
});
Is it possible to get this URL from the Management API, or do I need to use some other method. What is recommended?
Signed URLs created with the Firebase Admin SDK (backed by the the Cloud Storage SDK) are different from Download URLs created by the Firebase client SDKs. They serve the same general purpose, but you can expect them to look different from each other. They are both safe to store long term, except you should know that Signed URLs have an expiration date, which are you not specifying in your call. In that case, I don't know what the effective expiration is going to be.
Each invocation of getSignedUrl will generate a new URL. There is not just one that's unique to the file.

Resources