Add Extra Details on Firebase User Table

FirebaseAngularfireFirebasesimpleloginFirebase Authentication

Firebase Problem Overview


I'm working on a firebase+angularjs app and I'm using the simple email and password authentication and it's working properly.

I'm just wondering if I can add extra user data on the user table which is being used by firebase email+password auth, like I want to add billing info and other details concerning the user without creating extra node/table on firebase to store these extra data.

Firebase Solutions


Solution 1 - Firebase

Firebase stores the email/password users in a separate location, that you don't have direct access to. You cannot expand the data in this location.

Since many application developers want to access the user data in their application code, it is a common practice to store all users under a /users node inside the application database itself. The disadvantage is that you have to do this yourself. But the positive side of this is that you can store any extra information if you want.

See the Firebase guide on storing user data for sample code. From there:

var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.onAuth(function(authData) {
  if (authData && isNewUser) {
    // save the user's profile into Firebase so we can list users,
    // use them in Security and Firebase Rules, and show profiles
    ref.child("users").child(authData.uid).set({
      provider: authData.provider,
      name: getName(authData)
    });
  }
});

Solution 2 - Firebase

NOTE: This method only works if you are using Firebase Admin SDK and you need to have end point on your server to manage custom tokens

Firebase Admin SDK has an option to create custom tokens with additional claims object, which can contain arbitrary data. This might be useful to store some user related info, like whether the user is premium user or not.

Additional claims data is accessible using auth object.

example

var uid = "some-uid"; //this can be existing user UID
var additionalClaims = {
   premiumAccount: true,
   some-user-property: 'some-value'
};

admin.auth().createCustomToken(uid, additionalClaims)
  .then(function(customToken) {
     // Send token back to client
  })
  .catch(function(error) {
     console.log("Error creating custom token:", error);
});

additionalClaims are also accessible in Firebase security rules.

for more info read Firebase Custom Tokens

Solution 3 - Firebase

A Firebase User has a fixed set of basic properties—a unique ID, a primary email address, a name and a photo URL—stored in the project's user database, that can be updated by the user (iOS, Android, web). You cannot add other properties to the Firebase User object directly; instead, you can store the additional properties in your Firebase Realtime Database.

Solution 4 - Firebase

Firebase has a fixed set of user properties which can be updated but not added on to.

However you can add small amounts of data with the help of serialization and deserialization using JSON.stringify() and JSON.parse()

And then use any one of the unused properties to store the string

either in DisplayName, or photoURL property. Keep in mind the data that can be added has to be small in size and stored as a string.

And this can be only possible with using the method in the FIREBASE SDK and not the angularfire as illustrated below

var user = firebase.auth().currentUser;

user.updateProfile({
  displayName: "Jane Q. User",
  photoURL: "https://example.com/jane-q-user/profile.jpg"
}).then(function() {
  // Update successful.
}, function(error) {
  // An error happened.
});

You could store more json like data in the photoURL or displaYName variable in the form of string here.

Solution 5 - Firebase

My answer is not angular related but I searched quiet a bit to find out how to do it using Polymer and Polymerfire so I add this answer to help people get it done faster than i did.

I had to add a separate node to db as Frank van Puffelen mentioned.

Imports:

<link rel="import" href="../bower_components/polymerfire/firebase-app.html">
<link rel="import" href="../bower_components/polymerfire/firebase-auth.html">
<link rel="import" href="../bower_components/polymerfire/firebase-document.html">

Then place anywhere in your app a <firebase-app> component:

<firebase-app
  name="yourAppName"
  api-key= "{{yourApi}}"
  auth-domain= "{{yourAuthDomain}}"
  database-url= "{{yourDbUrl}}"
>
</firebase-app>

After that you will need to use <firebase-auth> and <firebase-document>:

Template :

<firebase-auth
  id="auth"
  app-name="yourAppName"
  signed-in="{{signedIn}}"
  user="{{user}}">
</firebase-auth>

<firebase-document
  id="document"
  app-name="yourAppName"
  path="{{usersPath}}"  // e.g "/users"
  data="{{userDocument}}">
</firebase-document>

Script:

this._register = function(){
  var formValid = this.querySelector('#register-form').validate();
  var auth = this.querySelector('#auth');
  if(formValid && this.passWordsIdentic){

  //The actual registration
  auth.createUserWithEmailAndPassword(this.email, this.password).then(function(user){
    console.log('auth user registration succes');

    //Example values
    this.userDocument.uid = user.uid;
    this.userDocument.email = user.email;
    this.userDocument.firstName = this.firstName;
    this.userDocument.lastName = this.lastName;
    this.userDocument.userName = this.userName;
    this.$.document.save(this.usersPath).then(() => {
        console.log("custom user registration succes");
        this.$.document.reset();
      });
     }.bind(this)).catch(function(error) {
       var errorCode = error.code;
       var errorMessage = error.message;
       console.log('error: ', errorCode);
     );
    }
  }

And that's it, you may want to take a look at this excellent google codelab which is a good introduction into using firebase with polymer.

Solution 6 - Firebase

Here is the code of registration where add the extra fields in the Users table

  import { AngularFireAuth } from "@angular/fire/auth";

  constructor(private firebaseAuth: AngularFireAuth){}

  registration(data: any, password: any) {
    return this.firebaseAuth.auth.createUserWithEmailAndPassword(data.Email, password)
      .then(res => {
        res.user.updateProfile({
          displayName: `${data.DisplayName}`
        })

    data.UserId = res.user.uid;
    data.PhoneNumbers = [{
      NumberType: '',
      NumberValue: ''
    }];

    data.PhotoUrl = '';
    data.Addresses = [{
      AddressLine1: '',
      AddressLine2: '',
      City: '',
      State: '',
      Country: '',
      PostalCode: '',
      AddressType: ''
    }];

    data.IsDeleted = false;
    this.fireStore.doc(`users/${res.user.uid}`).set(data);
    this.toastr.success('User has been register successfully!', 'Successfull!');
    return true;
  }).catch(err => {
    switch (err.code) {
      case 'auth/email-already-in-use':
        this.toastr.error(`Email address ${data.Email} already in use.`, 'Error!');
        break;
      case 'auth/invalid-email':
        this.toastr.error(`Email address ${data.Email} is invalid.`, 'Error!');
        break;
      case 'auth/operation-not-allowed':
        this.toastr.error('Error during sign up.', 'Error!');
        break;
      case 'auth/weak-password':
        this.toastr.error('Password is not strong enough. Add additional characters including special characters and numbers.', 'Error!');
        break;
      default:
        this.toastr.error(err.message, 'Error!');
        break;
    }
  });

}

Solution 7 - Firebase

Here's a swift version. Your user structure ("table") is like

--users:
-------abc,d@email,com:
---------------email:[email protected]
---------------name: userName
etc.

After you pass the auth FIRAuth.auth()?.createUser you can set the users in database as below:

        let ref = FIRDatabase.database().reference()
        let rootChild = ref.child("users")
        let changedEmailChild = u.email?.lowercased().replacingOccurrences(of: ".", with: ",", options: .literal, range: nil) // Email doesn't support "," firebase doesn't support "."
        let userChild = rootChild.child(changedEmailChild!)
        userChild.child("email").setValue(u.email)
        userChild.child("name").setValue(signup.name)

Solution 8 - Firebase

Please note that method is changed in v4.0.0. Therefore, you need to use the below code to retrieve the user profile:

afAuth.authState.subscribe((user: firebase.User) => { 
  this.displayName = user.displayName;
  this.email = user.email;
  this.photoURL = user.photoURL;
});

Solution 9 - Firebase

The answer from Frank is good, but things are a little different in Angular6/Firebase5/Angularfire5:

Here is my click handler for signing in a user:

this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()).then((e) => {
      console.log("Log-In Success" + e.additionalUserInfo.profile.name);
      if (e.additionalUserInfo.isNewUser)
        this.addUserToDatabase(/*...*/);
    }).catch((error) => {
      console.log("Log-In Error: Google Sign-In failed");
    });

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3440236View Question on Stackoverflow
Solution 1 - FirebaseFrank van PuffelenView Answer on Stackoverflow
Solution 2 - FirebaseHari PrasadView Answer on Stackoverflow
Solution 3 - FirebaseMirza Asad BaigView Answer on Stackoverflow
Solution 4 - FirebaseMagnus MelwinView Answer on Stackoverflow
Solution 5 - FirebaseGetter JetterView Answer on Stackoverflow
Solution 6 - FirebaseSimal ChaudhariView Answer on Stackoverflow
Solution 7 - FirebaseWilliam HuView Answer on Stackoverflow
Solution 8 - FirebaseGharibiView Answer on Stackoverflow
Solution 9 - FirebaseMike SpearView Answer on Stackoverflow