Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a custom auth token with a cloud function for firebase using the new 1.0 SDK

As of [email protected] and [email protected] firebase-admin no longer takes in an application config when the app initializes.

I had a firestore function that would generate a custom token using firebase-admin’s createCustomToken. Calling that function would generate a credential that I would pass into initializeApp in the credential attribute. How would I go about doing that now?

Do I need to edit process.env.FIREBASE_CONFIG somehow and put the serialized credential there before calling initializeApp?

like image 879
Murphy Randle Avatar asked Apr 04 '18 16:04

Murphy Randle


People also ask

What is custom token authentication?

What Are Custom Authentication Tokens? An authentication token is some data, represented as a string or XML, that identifies an entity (user or process), such as an X509 client certificate. Typically, authentication tokens are designed to be used within specific security protocols.

What is custom authentication in Firebase?

You can integrate Firebase Authentication with a custom authentication system by modifying your authentication server to produce custom signed tokens when a user successfully signs in. Your app receives this token and uses it to authenticate with Firebase.


2 Answers

Based on this issue in Github, it still works.

https://github.com/firebase/firebase-admin-node/issues/224

The following example worked for me:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');
admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: 'https://yourapplication.firebaseio.com/'
  });

exports.createToken = functions.https.onCall((data, context) => {
    const uid = context.auth.uid;
    return admin.auth()
                .createCustomToken(uid)
                .then(customToken => {
                    console.log(`The customToken is: ${customToken}`);
                    return {status: 'success', customToken: customToken};
                })
                .catch(error => {
                    console.error(`Something happened buddy: ${error}`)
                    return {status: 'error'};
                });
});
like image 108
Michael Chen Avatar answered Sep 20 '22 15:09

Michael Chen


Michael Chen's cloud function appears to trigger from a HTTP request from somewhere (an external server?). My employee wrote a cloud function that triggers when the user logs in:

// this watches for any updates to the user document in the User's collection (not subcollections)
exports.userLogin = functions.firestore.document('Users/{userID}').onUpdate((change, context) => {

  // save the userID ubtained from the wildcard match, which gets put into context.params
  let uid = context.params.userID;
  // initialize basic values for custom claims
  let trusted = false;
  let teaches = [];

  // check the Trusted_Users doc
  admin.firestore().collection('Users').doc('Trusted_Users').get()
  .then(function(doc) {
    if (doc.data().UIDs.includes(uid)) {
      // if the userID is in the UIDs array of the document, set trusted to true.
      trusted = true;
    }

    // Get docs for each language in our dictionary
    admin.firestore().collection('Dictionaries').get()
    .then(function(docs) {
      // for each of those language docs
      docs.forEach(function(doc) {
        // check if the userID is included in the trustedUIDs array in the doc
        if (doc.data().trustedUIDs.includes(uid)) {
          // if it is, we push the 2-letter language abbreviation onto the array of what languages this user teaches
          teaches.push(doc.data().shortLanguage);
        }
      });

      // finally, set custom claims as we've parsed
      admin.auth().setCustomUserClaims(uid, {'trusted': trusted, 'teaches': teaches}).then(() => {
        console.log("custom claims set.");
      });
    });
  });
});

First, we put in a lastLogin property on the user object, which runs Date.now when a user logs in and writes the time to the database location, triggering the cloud function.

Next, we get the userID from the cloud function response context.params.userID.

Two variables are then initialized. We assume that the user is not trusted until proven otherwise. The other variable is an array of subjects the user teaches. In a roles-based data security system, these are the collections that the user is allowed to access.

Next, we access a document listing the userIDs of trusted users. We then check if the recently logged in userID is in this array. If so, we set trusted to true.

Next, we go to the database and traverse a collection Dictionaries whose documents include arrays of trusted userIDs (i.e., users allowed to read and write those documents). If the user is in one or more of these arrays, he or she gets that document added to the teaches property on his or her user data, giving the user access to that document.

Finally, we're ready to run setCustomUserClaims to customize the token claims.

like image 28
Thomas David Kehoe Avatar answered Sep 17 '22 15:09

Thomas David Kehoe