I have implemented firebase auth in my app. I need to update the photo URL using a Cloud Function. So when the user uploads a photo to storage, I need to update the URL in the user object with the URL of the image which is uploaded at images/uid.png
I need to find the user by uid and then update the user object with the new URL but I cannot do that. This what I have tried:
exports.updateUrl = functions.auth.getUser(uid)(async (user) => {
const newPhotoUrl = storage.bucket().file(`images/${uid}.jpg`);
await admin.auth().updateUser(user.uid, {photoUrl: newPhotoUrl});
return true;
});
I've found this answer but it contains only broken links :(
How to solve this?
When the user uploads a photo to storage
This means that you need to use a Cloud Function that is triggered by a Cloud Storage event and not a CF triggered by the Authentication Service event (BTW functions.auth.getUser()
does not exist, see the doc).
The following should do the trick (untested).
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp()
exports.updateUrl = functions.storage.object().onFinalize(async (object) => {
try {
const newPhotoStorageFile = admin.storage().bucket(object.bucket).file(object.name);
const signedURLconfig = { action: 'read', expires: '01-01-2030' };
const newPhotoURLArray = await newPhotoStorageFile.getSignedUrl(signedURLconfig);
const newPhotoURL = newPhotoURLArray[0];
const newPhotoStoragePath = object.name;
const userId = newPhotoStoragePath.split("/")[1].split(".")[0]; // Double check this simple extraction code is valid for all your cases.
await admin.auth().updateUser(userId, { photoUrl: newPhotoURL });
return true;
} catch (error) {
console.log(error);
return null;
}
});
At this stage if you run this Cloud Function you'll get the following error: Error: Permission 'iam.serviceAccounts.signBlob' denied on resource (or it may not exist)
.
Assigning, via the Google Cloud console, this IAM permission to the App Engine default service account, PROJECT_ID @appspot.gserviceaccount.com
would solve the problem.
HOWEVER, you would face another problem: The SignedURL has a short life duration due the problem described in this SO answer. So you need to use the Google Cloud Storage npm module and initialize it with a service account json file.
const {Storage} = require('@google-cloud/storage');
const storage = new Storage({keyFilename: "key.json"});
const newPhotoStorageFile = storage.bucket(object.bucket).file(object.name);