Best practices for authenticating using Firebase | Firebase Developers

Best practices for authenticating using Firebase

Louis Japheth Kouassi
Firebase Developers
8 min readNov 5, 2023

--

Authentication is the process of verifying who a user is. Authorization is the process of determining what a user has access to, which is essential to protect the data in your application. Firebase provides a powerful and flexible way to implement this using Firebase Authentication and Security Rules.

People usually prefer to use apps and browse the web without having to identify themselves each time, either by signing in or by registering for a new account with their personal information.

In many cases, there are three main reasons why users need to identify themselves:

  • Associate data with a user ;
  • Limit the number of users ;
  • Set up administrative control;

To ensure the security of the application and the user data, an authentication policy must be implemented to verify user identity. This policy must be implemented using appropriate technology. Today, some services and technologies offer secure authentication systems that make our jobs easier. In this regard, Google’s Firebase platform offers many options to meet your authentication needs.

Authentication is an important element of application security, but it can also be a barrier to adoption. For example, many applications require users to create an account before they can use them. This can discourage potential users who are not always willing to commit in advance. One solution is to offer a trial version of the application that does not require registration. This would allow users to try the application before creating an account. Another solution is to use a simple authentication method, such as email or phone number authentication. This would allow users to log in quickly and easily. Ultimately, the goal is to strike a balance between security and accessibility.

Firebase offers many options that can accommodate your authentication needs :

1. Anonymous authentication

import { getAuth, signInAnonymously } from "firebase/auth";

const auth = getAuth();
signInAnonymously(auth)
.then(() => {
// Signed in..
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});

For web applications, we recommend calling Firebase’s signInAnonymously() function early in the application lifecycle, before using other Firebase services that require an identifier. This will associate user interactions with the UID assigned to the guest account.

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in
const uid = user.uid;
// ...
} else {
// User is signed out
// ...
}
});

During an anonymous connection, the onAuthStateChanged listener is called. The user object is passed to the listener’s callback function, which retrieves the user’s identifier.

When logging in anonymously, the user’s identifier is stored on his or her device, in an area inaccessible to other applications. This means that the user cannot log in to their anonymous account on another device. To enable users to log in from different devices, it is necessary to convert their anonymous accounts into permanent accounts. This is done by connecting the anonymous identifier to an authentication system with a permanent identifier.

import { getAuth, linkWithCredential } from "firebase/auth";

const auth = getAuth();
linkWithCredential(auth.currentUser, credential)
.then((usercred) => {
const user = usercred.user;
console.log("Anonymous account successfully upgraded", user);
}).catch((error) => {
console.log("Error upgrading anonymous account", error);
});

When users are ready, they can create an account using their permanent credentials. These credentials can be generated by a permanent authentication system, such as a Google or Facebook account. Account linking connects the original anonymous user account to the verified user account. No data is lost because you can use linkWithCredential to connect the credentials of the permanent sign-in mechanism to the original anonymous user account.

2. Password authentication

  • E-mail and password authentication is a common and easy-to-use option. Users only need one password to access an application and its data. But is it secure 🤔? Let’s take a look!
import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";

const auth = getAuth();
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ..
});
  • Firebase’s email and password authentication can be implemented in a single line of code, which can be misleading. In reality, it is necessary to implement additional flows to make the system secure, such as email verification and password reset. Firebase’s email and password authentication is a simple and effective solution, but it requires a few extra steps to make it secure. It is important to implement password verification and reset workflows to protect users against identity theft and account loss.
  • Email and password authentication is a single-factor security method. Since e-mail addresses are often public or easy to guess, only one piece of information is needed to access an account: the password.
  • Passwords alone are not very secure. Hackers can steal or guess them, giving them full access to the account. To reinforce security, it is necessary to add another authentication factor.

Passwords are a weak link in the security chain. You can do without them, and it’s easier than you think.

Passwords are often weak, making them easy to guess or crack. They are also used for multiple applications, increasing the risk of exposure if a single password is compromised. Finally, passwords must be recovered or reset if forgotten or compromised. Firebase Authentication supports both sending the verification email and resetting the password.

3. Federated authentication providers

In addition to logging in with a Firebase account, you can also offer your users log-in with an account from a trusted third-party provider. Firebase offers SDKs compatible with several federated identity providers, such as Google Sign-In, Sign in with Apple, Microsoft, Facebook and GitHub.

When it comes to choosing an identity provider, it makes sense to focus on the provider for the platform in question. For example, use Google Sign-In for Android and Sign in with Apple for iOS. However, if you choose to use an identity provider on one platform, you need to support it on all the other platforms on which your application runs. Otherwise, a user with an Android phone and an iPad won’t be able to log in to your app on all their devices.

import { getAuth, getRedirectResult, GoogleAuthProvider } from "firebase/auth";

const auth = getAuth();
getRedirectResult(auth)
.then((result) => {
const credential = GoogleAuthProvider.credentialFromResult(result);
const token = credential.accessToken;
const user = result.user;
// ...
}).catch((error) => {
// ...
});

The example above shows how to use Google Sign-In with a web application. The application uses a redirect to the Google sign-in page, which is the recommended method for mobile devices.
However, it should be noted that a redirect does not work on browsers that block third-party cookies. Fortunately, there are some solutions available.

import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";

const auth = getAuth();
const provider = new OAuthProvider("apple.com");
signInWithPopup(auth, provider)
.then((result) => {
const credential = OAuthProvider.credentialFromResult(result);
const accessToken = credential.accessToken;
const idToken = credential.idToken;
const user = result.user;
// ...
})
.catch((error) => {
// ...
});

One of these solutions is the Sign in with Apple. Instead of redirecting the user to another website, a pop-up window appears on the user’s device.
If you use a federated identity provider to connect to your application, you should also use Sign in with Apple for Apple users. This is good practice, as Apple users expect to be able to log in with their Apple ID.

4. Multi-factor authentication

Applications using Firebase Authentication with Identity Platform can add multi-factor authentication, in addition to existing authentication methods.
Multi-factor authentication is more secure than single-factor authentication because it adds an extra layer of security. This extra layer consists of a second factor, such as an e-mail or text message, which is difficult to intercept.

  • SMS auth

SMS is a popular second-factor option supported by Firebase. You may have already used it to connect to an application.
Before implementing SMS as a second factor, it’s important to consider the needs of your users. Some users may not expect a phone message to be necessary to connect. In addition, phone numbers sometimes change, which can cause problems for users who travel or use the application on multiple devices. Finally, users have to manually enter the code received on their phone, which can be a source of inconvenience.

  • TOTP auth

A more secure option is to use a one-time password generated by an authentication application such as Google Authenticator. These applications generate a new code every few seconds, making it more difficult for hackers to access your account.
Here’s how to add two-factor authentication to your application:

import {
getAuth,
getMultiFactorResolver,
TotpMultiFactorGenerator,
} from "firebase/auth";

try {
const userCredential = await signInWithEmailAndPassword(
getAuth(),
email,
password
);
// User is not enrolled with a second factor...
} catch (error) {
if (error.code === "auth/multi-factor-auth-required") {
// Initiate your second factor sign-in flow
}
}

TOTP is a second authentication factor that comes into play after initial authentication. This code uses the signInWithEmailAndPassword method. If the connection is successful, the second factor is not yet activated. On the other hand, if the connection fails with the message “multi-factor-auth-required”, we can proceed to the next step.

const mfaResolver = getMultiFactorResolver(getAuth(), error);
const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
const {factorId, uid} = mfaResolver.hints[selectedIndex];

if (factorId === TotpMultiFactorGenerator.FACTOR_ID) {
const otpFromAuthenticator = // OTP typed by the user.
const multiFactorAssertion =
TotpMultiFactorGenerator.assertionForSignIn(
uid,
otpFromAuthenticator
);
try {
const userCredential = await mfaResolver.resolveSignIn(
multiFactorAssertion
);
// Successfully signed in!
} catch (error) {
// Invalid or expired OTP.
}
}

Once we’ve identified the TOTP resolver used, for example Google Authenticator, we request and retrieve the user’s one-time password. We can then use the SDK’s assertionForSignIn method to resolve the second authentication factor. And there you have it: highly secure multi-factor authentication! 🥳

Hopefully, you’ll have a large user base to authenticate — millions of users! Make sure every one of them has a smooth and secure login experience for your Firebase application.

See you soon for another article on how to use Firebase products on your app! 😎

--

--

Louis Japheth Kouassi
Firebase Developers

I am passionate about Google Firebase, PWA, AI/ML Techs. I like to learn, share and learn from others. GDG+TFUG Bassam Lead! Twitter: @LouisKouassii