EmberFire Authentication and ToriiFirebaseAdapter

1k views Asked by At

I've followed the EmberFire guide to setting up authentication with the torii provider and it works perfectly. I'm looking to store the users data in firebase after the user has been authenticated and to have access to the user object throughout the application.

I have previously done this with ember awhile back but i'm unsure how to do it using the new torii provider.

I'm thinking i should test wether the user is already stored in firebase in an initialiser function and then inject the user into the controllers/routes.

Any help pointing me in the right direction would be helpful or some example code.

Thanks

2

There are 2 answers

5
tstirrat On BEST ANSWER

You need a Torii adapter that implements open and fetch and does a find/save to your app specific user model. Our ToriiFirebaseAdapter does not do this, yet. I've gone ahead and knocked one up for you that will work:

// app/torii-adapters/application.js

import Ember from 'ember';

export default Ember.Object.extend({
  firebase: Ember.inject.service(),
  store: Ember.inject.service(),

  /**
   * Executed after Firebase authentication.
   *
   * Find or create the user based on the Firebase `authData`
   *
   * @param  {Object} authData
   * @return {Promise<Object>} Updated session info
   */
  open(authData) {
    return this._findOrCreateUser(authData)
      .then((user) => {
        return { currentUser: user };
      });
  },

  /**
   * Fetch an existing Firebase auth session and place into `session.currentUser`
   *
   * @return {Promise<Object>} Updated session info
   */
  fetch() {
    let ref = this.get('firebase');
    let authData = ref.getAuth();

    if (!authData) {
      return Ember.RSVP.Promise.reject(new Error('No Firebase session found'));
    }

    return this._findOrCreateUser(authData)
      .then((user) => {
        return { currentUser: user };
      });
  },

  /**
   * Teardown a session. Remove the `session.currentUser`.
   *
   * @return {Promise<Object>} Updated session info
   */
  close() {
    this.get('firebase').unauth();
    return Ember.RSVP.Promise.resolve({ currentUser: null });
  },

  /**
   * Find the user with the given `authData`, create if not found
   *
   * @param  {Object} authData
   * @return {Promise<Object>} The user
   */
  _findOrCreateUser(authData) {
    let store = this.get('store');

    return store.find('user', authData.uid)
      .catch(() => {
        let newUser = store.createRecord('user', this.extractUserProperties(authData));

        return newUser.save();
      });
  },

  /**
   * Extract the user properties from `authData` that you care about.
   *
   * @param  {Object} authData
   * @return {Object} An updated property hash
   */
  extractUserProperties(authData) {
    var name = 'Unknown';
    var provider = authData.provider;
    var userData = authData[provider];

    if (userData.displayName) {
      name = userData.displayName;
    } else if (userData.username) {
      name = userData.username;
    }

    return {
      id: authData.uid,
      name: name,
      email: userData.email || null
    };
  }
});

All you need to do is update the extractUserProperties method to get the properties you care about into their correct place on your user model - everyone implements their user model differently.

Now you should be able to look up session.currentUser and it will return an Ember Data model that corresponds to the logged in user.

Hope that helps. We are in the process of adding this to the website documentation and will try to find a way to roll this into the EmberFire supplied ToriiFirebaseAdapter.

0
cs3b On

I would recommend to always look at base adapter:

There you can find that the only method you have to overwrite is open.

My solution isn't perfect, still you can also look at this (it works well with google oauth).

import Ember from 'ember';
import ToriiFirebaseAdapter from 'emberfire/torii-adapters/firebase';

export default ToriiFirebaseAdapter.extend({
  firebase: Ember.inject.service(),
  store: Ember.inject.service(),

  open(authentication) {
    return this._findOrCreateUser(authentication.uid, authentication[authentication.provider])
      .then(user => Ember.RSVP.resolve({
        provider: authentication.provider,
        uid: authentication.uid,
        currentUser: user
      }));
  },

  _findOrCreateUser(uid, userData) {
    let store = this.get('store');
    return store.findRecord('user', uid).then(
      function (user) {
        user.set('name', userData.displayName);
        user.set('imageUrl', userData.profileImageURL);
        user.save();
        return user;
      },
      function () {
        let user = store.createRecord('user', {
          id: uid,
          name: userData.displayName,
          imageUrl: userData.profileImageURL
        });
        user.save();
        return user;
      }
    );
  },
});