A Bit of Background…
It is a common use case for me that I work on projects for clients where i’m building tools that are meant to be used internally by their business’s employees. Think of tools like an intranet or a CRM. In this case we would like any employee of the company to be able to log in. Its also common for users to have a default level of access. This process should also be self-serve so employees can create their own account without having an approval process.
Luckily, Firebase has some mechanisms that help make this simple. While this feature is not built-in to Firebase, it does provide tools via their authenication SDKs and security rules to make this work without too much hassle.
What is Firebase Auth
Firebase Auth is a part of Google’s Firebase suite of products that handles logging in.
- Email & Password Login
- Google Sign-in
- Facebook Sign-in
- Twitter Sign-in
- GitHub Sign-in
- Phone Number Authentication
- Anonomous Sign-in
Why would I use Firebase Auth
There are a lot of reasons why someone would:
- A unified API for multiple authentication providers
- It’s completely Free
- It’s secure
- It is HIPAA Complian (via Google’s Identity Platform)
Step 1: Server-side restrictions
The way that we restrict login access to specific domains is through Firebase’s Security Rules.
The first thing we need to do is create a function to validate an account:
function validAccount(userEmail){
return userEmail.split('@')[1] == 'mydomain.com';
}
This function will split an email on the @
sign and then we check if the second item in that array is equal to your authorized domain. This will return true
or false
.
Next, we’ll set up security rules:
match /Employees {
match /{userId} {
// allow user to read from Employees collection
// if logged in and is an authorized account
allow read: if request.auth != null
&& validAccount(request.auth.token.email);
// Avoid editing another person's profile
allow write: if request.auth.uid == userId
&& validAccount(request.auth.token.email);
}
}
This will ensure that only users from the authorized domain can read from the collection and only the user can edit their own profile. More on this next.
Step 2: Client-side
Now we have to test & enforce these rules client site. In this example we’re going to use the Web SDK (JavaScript), but this mechanism exists in all of Firebase Auth’s client libraries.
function googleLogin() {
const provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({
hd: 'mydomain.com'
});
firebase.auth()
.signInWithPopup(provider)
.then(() => validateAccountCheck => {
if(validAccount) {
// do something here like update the page
} else {
//sign user out if not valid
firebase.auth().signOut()
}
})
}
function validateAccountCheck() {
const user = firebase.auth.currentUser;
let profileInfo = {
displayName: user.displayName,
email: user.email,
photoURL: user.photoURL
};
return db
.collection('Employees')
.doc(user.id)
.set(profileInfo, { merge: true })
.then(() => true)
.catch(err => {
// not an authorized user
console.log(err)
false;
})
}
Here is a breakdown of what is going on. First a few definitions:
googleLogin
is the method that gets called when a user clicks the “sign in with Google” buttonprovider.setCustomParameters
pre fills the login form with the login domain.signInWithPopup
launches the Google sign in dialog in a new window. After signing in it calls thevalidateAccountCheck
function. If it succeeds do something, else log out.validateAccountCheck
gets the current (signed in) user and sets the user’s name, email, and photo from their Google account to their record in the Employees collection.
As a result of the security rules set above a user is only allowed to write to a record in the Employees
collection if the userId
of the user and the uid
of the record match.