Create user data for new Firebase auth accounts

in #firebase7 years ago (edited)

This Firebase kindling will describe a simple recipe for creating a user profile document and upload a profile picture upon new account creation with Firebase authentication.

If you have been working with Firebase before, you might have found yourself creating a "user" object to complement the information that we retrieve from Firebase authentication. If you are new to Firebase, you are likely to find this article useful in a very near future.

Preconditions

You will need to install the crypto-js NPM package dependency for your cloud functions. We'll be using the MD5 hash function for fetching gravatar images.

~/awesomeproject $ cd functions
~/awesomeproject/functions $ npm i --save crypto-js

Before you go any further, you need to know that your project must be on a "non-free price plan" to use the code in this example. Blaze is a pretty good choice if you don't know which one to choose. And it's worth mentioning that you do not pay for your usage even if you're on the Blaze plan, iff you are below the free usage tier levels.

That means that your project won't cost you anything until you reach higher usage. But instead of just hitting the breaks, which is a bad experience even in Alpha testing, you will start paying some $$$. Try to have a plan to make up for that when you develop your app.

What are we cooking?

Here's what we'll do: for every new account that is created through Firebase authentication, we'll create a "user document" in Firestore containing the name, email and profile photo. The profile photo will be saved to Cloud Storage for Firebase ... but not only that, we'll try and fetch the user's gravatar if the Firebase auth object did not cointain any profile photo (commonly if the user signed up with email/password).

The code

import * as functions from "firebase-functions";
import * as firebase from "firebase-admin";
import {MD5} from "crypto-js";

export const createUserDoc = functions.auth.user().onCreate(event => {
    const firebaseUser = event.data;

    // Use gravatar as default if photoUrl isn't specified in user data
    let fileEnding = "jpg";
    let photoURL = `https://www.gravatar.com/avatar/${MD5(firebaseUser.email).toString().toLowerCase()}.jpg?s=1024&d=robohash`;
    if (firebaseUser.photoURL) {
        fileEnding = firebaseUser.photoURL.substr(firebaseUser.photoURL.lastIndexOf(".") + 1);
        photoURL = firebaseUser.photoURL;
    }
    
    const fileName = `users/${firebaseUser.uid}/profile.${fileEnding}`;
    const profilePhotoStorageOpts = {
        destination: fileName,
        metadata: {
            contentType: `image/${fileEnding}`
        }
    };

    const user = {
        name: firebaseUser.displayName || "No Name",
        email: firebaseUser.email,
        photoUrl: `gs://${firebase.storage().bucket().name}/${fileName}`
    };

    return Promise.all([
        firebase.storage().bucket().upload(photoURL, profilePhotoStorageOpts),
        firebase.firestore().collection("users").doc(firebaseUser.uid).set(user)
    ]);
});

Breakdown

I have those from time to time. But we can talk about that another time. Let's break down the code in the example above.

First we're getting a UserRecord object passed in the event parameter. The property values of that object will depend on the authentication type that was used (email/password, Google, Twitter, etc). Most relevant for this example is that the email/password authentication will not provide any data in the photoURL attribute.

Since we might not get a photoURL from the user object, we're preparing the default values for user's profile photo with a gravatar URL that even provides us with a fallback image, in case the user doesn't have a gravatar profile either. So no matter what, we'll end up with a user profile pic in the end.

After that, we're allowing for the Firebase UserRecord to overwrite the gravatar profile image, if there is a photoURL present (i.e. if the user logged in with a with any of the federated identity providers.

We prepare a path for the user profile image to be stored at. It's good practice to use the user's UID in the path so that you can create good Storage security rules.

Storing the content type together with the image helps when you're retrieving the image later. So that the file type can be determined in a HTTP GET request, not just interpreted by its file ending.

Create the user object with a link to your bucket and file, this will give you an internal link directly to the cloud storage, that will be easy to use with the Firebase SDK for referring to the image later.

Finally, upload the image. And you might have noticed that here's that wonderful Firebase SDK magic at its best: you can upload the photo just by providing the URL. Let Firebase do the work of fetching it.

Result

For each created account you will now find a corresponding user document in Firestore and a profile image in the cloud storage.

Profile photo in cloud storage

Profile photo in cloud storage

User doc in Firestore

Firestore user doc

User account in Firebase auth

Firebase auth

Homework

To complete the snippet above you might want to add in some error checking and graceful fallback if anything should go wrong with file upload for example (e.g. bad response from gravatar.com).

Subscribe if you liked it

Please like the article if you enjoyed reading it and don't forget to subscribe to more articles like this on Medium and Steemit

Let me know in the comment section below if you have any questions or feedback. I'd love to hear from you.

Sort:  

This wonderful post has received a @dennisalund 27.99% upvote from @hellowhale. Discord Channel: https://discord.gg/XG4y3mg You can vote in the name of the odl. https://steemit.com/~witnesses

You got a 1.02% upvote from @postpromoter courtesy of @dennisalund! Want to promote your posts too? Check out the Steem Bot Tracker website for more info. If you would like to support development of @postpromoter and the bot tracker please vote for @yabapmatt for witness!

Your Post Has Been Featured on @Resteemable!
Feature any Steemit post using resteemit.com!
How It Works:
1. Take Any Steemit URL
2. Erase https://
3. Type re
Get Featured Instantly – Featured Posts are voted every 2.4hrs
Join the Curation Team Here

Hi Mr.Dennis, I'm iqbal @iqbalhood, last month we met at Clapham Startupfest Medan, welcome to join steemit, I hope there will be many posts about firebase here :)