Firebase custom Auth with Microsoft Azure / Graph
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
In your
index.js
file, you can get your service file by entering this code:const admin = require('firebase-admin');
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
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 regularJSON
file that contains whatever you want to add to the users Firebase account.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
When your client received the token you a custom auth sign in iOS or in Android as described in the documentation.
You are now authenticated both towards Firebase and Microsoft
I have also added an extra layer of security, by checking that the
ID
i got from Microsoft, is the sameID
stored in the authenticated account from Firebase.
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