Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase custom Auth with Microsoft Azure / Graph

I'm building an enterprise app using Microsoft Graph to sign in. After a successful signing i want to use the token to be sent to authenticate to Firebase Auth (so i can secure the access to the database).

The token recieved after a successful sign in cannot be used directly to Firebase.

On the Firebase custom Auth instructions page it says:

Get your project's server keys:

  1. Go to the Service Accounts page in your project's settings.
  2. Click Generate New Private Key at the bottom of the Firebase Admin SDK section of the Service Accounts page.
  3. The new service account's public/private key pair is automatically saved on your computer. Copy this file to your authentication server.

The third point says that you need to enter the key to the authentication server. Is this possible using Microsoft Graph or Azure AD?

The key that Firebase gives you is a JSON file. I've checked Microsoft App registration portal which allows you to edit the apps Manifest, but with no luck.

The JSON file looks like this:

{
    "type": "service_account",
    "project_id": "APP_ID",
    "private_key_id": "KEY_ID_VALUE",
    "private_key": "-----BEGIN PRIVATE KEY----<KEY VALUE>-----END PRIVATE KEY-----\n",
    "client_email": "firebase-adminsdk-0ubvc@********.iam.gserviceaccount.com",
    "client_id": "XXXXXXXXXXXX",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-0ubvc%XXXXXXXX.iam.gserviceaccount.com"
}

I can't seem to find any github projects or stackoverflow threads that covers this issue.

How can you recieve custom tokens with MS Graph or Azure AD?

like image 233
Giovanni Palusa Avatar asked Nov 02 '17 12:11

Giovanni Palusa


3 Answers

I have now fully worked this out. Through extensive research and a lot of help here on Stackoverflow i managed to solve this.

UPDATE

Database secrets are currently deprecated and use a legacy Firebase token generator. Now Firebase Admin import is good enough.

so, these are my findings:

1. You DO need to send your private keys to your firebase functions when minting a Firebase Token. In the Firebase console, you can extract the key and rename the file to service-account.json. This should be put in your Functions folder before performing your Firebase deploy

  1. In your index.js file, you can get your service file by entering this code:

    const admin = require('firebase-admin');
    
  2. Write the function for accepting information from the other Authentication service:

    // Create a Firebase token from any UID
    exports.createFirebaseToken = functions.https.onRequest((req, res) => {
    
      // The UID and other things we'll assign to the user.
      const uid = req.body.uid;
      const additionalClaims = {
        name: req.body.name,
        email: req.body.email
      };
    
      // Create or update the user account.
      const userCreationTask = admin.auth().updateUser(uid, additionalClaims).catch(error => {
    
        if (req.method === 'PUT') {
          res.status(403).send('Forbidden!');
        }
    
        if (req.method === 'GET') {
         res.status(403).send('Please use POST for this function');
        }
    
        // If user does not exists we create it.
        if (error.code === 'auth/user-not-found') {
          console.log(`Created user with UID:${uid}, Name: ${additionalClaims.name} and e-mail: ${additionalClaims.email}`);
          return admin.auth().createUser({
          uid: uid,
          displayName: additionalClaims.name,
          email: additionalClaims.email,
        });
            }
            throw error;
            console.log('Error!');
        });
    
    
        return Promise.all([userCreationTask]).then(() => {
          console.log('Function create token triggered');
          // Create a Firebase custom auth token.
          admin.auth().createCustomToken(uid, additionalClaims).then((token) => {
          console.log('Created Custom token for UID "', uid, '" Token:', token);
            res.status(200).send(token);
            return token
        });
      });
    });
    

It's very important to respond with a res.status since this will finish the task. A single return statement will not do this. A fully working sample from Firebase themself can be found on github

  1. You can now make a HTTP-request that could look something like this using Alamofire and swift

    Alamofire.request("https://us-central1-<YOUR DATABASE REFERENCE>.cloudfunctions.net/createFirebaseToken", 
    method: .post, parameters: parameters, encoding: JSONEncoding.default).
    responseString(completionHandler: { (token) in
        // Handle the result here
    })
    

    In this case, the Parameters is a regular JSON file that contains whatever you want to add to the users Firebase account.

  2. IMPORTANT Anyone with your cloudfunctions URL can trigger this token minting. So make sure you add security measures to handle this. This is briefly mentioned in a Firecast video on youtube made by Firebase and has also been discussed in this thread in Stackoverflow

  3. When your client received the token you a custom auth sign in iOS or in Android as described in the documentation.

  4. You are now authenticated both towards Firebase and Microsoft

  5. I have also added an extra layer of security, by checking that the ID i got from Microsoft, is the same ID stored in the authenticated account from Firebase.

like image 169
Giovanni Palusa Avatar answered Nov 06 '22 16:11

Giovanni Palusa


I've created an example here for Firebase web and browser-based federated authentication. The authentication response from Azure AD is validated by a function, a custom firebase token is minted and sent to the front-end; which is sent to the Firebase Auth service.

Guide with more elaboration on the flow: https://medium.com/@alex.wauters/how-to-integrate-a-firebase-web-app-with-azure-active-directory-b5c0f01a0c24

like image 21
Alex Wauters Avatar answered Nov 06 '22 18:11

Alex Wauters


It's a lot simpler than you think. After you authenticate with Microsoft, and you get a Microsoft credential, you just need to get the associated Microsoft user ID for that credential. You can then mint a Firebase custom token and set the Firebase uid to that same Microsoft user ID. For example you can do it as follows with the Firebase Admin Node.js SDK:

admin.createCustomToken(msftUid, additionalUserClaims)
  .then(customToken => {
    // Return this to the client.
  })

After you send it back to the client, you then call signInWithCustomToken(customToken) which would sign in the same user with Firebase Auth. That user will have currentUser.uid equal to the Microsoft user ID.

like image 1
bojeil Avatar answered Nov 06 '22 17:11

bojeil