Firebase Custom Authentication Using Cloud Functions

Firebase Custom Authentication offers a flexible solution for generating custom tokens with our own authentication logic. These tokens can be used to authenticate users in your Firebase project and making it ideal for integrating existing user systems, third-party authentication providers or custom authentication mechanisms.

In this article, We will learn about Firebase Custom Authentication along with Setting up a Firebase Custom Authentication Using Cloud Functions in detail.

Introduction to Firebase Custom Authentication

  • Firebase Custom Authentication allows us to generate custom tokens with our authentication logic.
  • These tokens can then be used to authenticate users in our Firebase project.
  • This is useful for integrating existing user systems, third-party authentication providers or custom authentication mechanisms.

Prerequisites

Before getting started, ensure you have:

  • A Firebase project.
  • Node.js installed.
  • Firebase CLI installed.

Step 1: Set Up Firebase Project and Initialize Cloud Functions

Create a Firebase Project

  • Go to Firebase Console: Navigate to the Firebase Console.
  • Add a New Project: Click on “Add project” and enter your project name, configure Google Analytics (optional) and click “Create Project.”

Initialize Cloud Functions

  • Install Firebase CLI:
npm install -g firebase-tools
  • Login to Firebase
firebase login
  • Initialize Firebase Functions:

Navigate to your project directory and run:

firebase init functions

Follow the prompts to set up your project and choose to use JavaScript for writing functions.

  • Install Dependencies

Navigate to the functions directory and install the necessary dependencies:

cd functions
npm install firebase-admin firebase-functions

Step 2: Create a Custom Authentication Token

  • To create custom authentication tokens, we will use Firebase Admin SDK.
  • In our functions directory, open the index.js file and add the following code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp();

exports.createCustomToken = functions.https.onRequest((req, res) => {
const uid = req.body.uid;

admin.auth().createCustomToken(uid)
.then((customToken) => {
res.status(200).send({ token: customToken });
})
.catch((error) => {
console.error("Error creating custom token:", error);
res.status(500).send({ error: 'Error creating custom token' });
});
});

Explanation

  • Initialize Firebase Admin SDK: The admin.initializeApp() function initializes the Firebase Admin SDK.
  • Cloud Function: The createCustomToken function is an HTTP endpoint that receives a user ID (uid), generates a custom token for that user, and sends the token back in the response.

Deploy the Function

Deploy your Cloud Function using the Firebase CLI:

firebase deploy --only functions

Step 3: Authenticate with Custom Tokens in Your Application

After deploying the Cloud Function, we can call this function from our client application to generate a custom token and use it to authenticate the user.

Client-Side Setup

Add Firebase SDK to Your Project:

Include the Firebase SDK in our HTML file or install it via npm if we are using a module bundler:

<!-- Add Firebase SDK -->
<script src="https://www.gstatic.com/firebasejs/9.0.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.0.0/firebase-auth.js"></script>

Or, if using npm:

npm install firebase

Initialize Firebase in Your Application:

// Initialize Firebase
import { initializeApp } from "firebase/app";
import { getAuth, signInWithCustomToken } from "firebase/auth";

const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
databaseURL: "YOUR_DATABASE_URL",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID"
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);

Call the Custom Token Endpoint and Authenticate the User:

async function authenticateUser(uid) {
try {
// Call the custom token endpoint
const response = await fetch('https://YOUR_REGION-YOUR_PROJECT_ID.cloudfunctions.net/createCustomToken', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ uid })
});

const data = await response.json();
const customToken = data.token;

// Authenticate with the custom token
const userCredential = await signInWithCustomToken(auth, customToken);
console.log('User authenticated:', userCredential.user);
} catch (error) {
console.error('Error authenticating user:', error);
}
}

// Example usage
authenticateUser('unique_user_id');

Explanation

  • Fetch Custom Token: The fetch call sends the user ID to the Cloud Function endpoint and retrieves the custom token.
  • Sign In with Custom Token: The signInWithCustomToken function authenticates the user with the retrieved custom token.

Step 4: Testing the Authentication Flow

To test the authentication flow, you can create a simple HTML page with an input field for the user ID and a button to trigger the authentication:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Firebase Custom Authentication</title>
</head>
<body>
<h1>Firebase Custom Authentication</h1>
<input type="text" id="uid" placeholder="Enter User ID">
<button onclick="authenticateUser()">Authenticate</button>

<script src="app.js"></script>
<script>
async function authenticateUser() {
const uid = document.getElementById('uid').value;
if (uid) {
try {
const response = await fetch('https://YOUR_REGION-YOUR_PROJECT_ID.cloudfunctions.net/createCustomToken', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ uid })
});

const data = await response.json();
const customToken = data.token;

const userCredential = await signInWithCustomToken(auth, customToken);
console.log('User authenticated:', userCredential.user);
} catch (error) {
console.error('Error authenticating user:', error);
}
} else {
alert('Please enter a user ID');
}
}
</script>
</body>
</html>

Output:

Explanation

  • User Input: The input field allows the user to enter their user ID.
  • Button: The button triggers the authenticateUser function, which calls the custom token endpoint and authenticates the user with the retrieved token.

Conclusion

Overall, Firebase Custom Authentication using Cloud Functions provides a powerful way to integrate custom authentication logic into your Firebase applications. By following the steps outlined in this guide, you can set up a Firebase project, create Cloud Functions to generate custom tokens, and authenticate users using these tokens in your JavaScript application. This approach helps to create customization and control over the authentication process and allows you to customize it to your specific requirements.