Phone number authentication using Firebase 9 in Laravel 9 with Tailwindcss

Phone number authentication using Firebase 9 in Laravel 9 with Tailwindcss

Using firebase web version 9 modular to authenticate user phone number in a Laravel application with tailwindcss

Table of contents

No heading

No headings in the article.

In this article, we'll be looking at how to authenticate a user's phone number using firebase web version 9 modular in a Laravel application.

Phone numbers can be verified on Laravel using the firebase phone authentication service.

Firebase: Firebase is an app development platform that helps you build and grow apps and games users love. Backed by Google and trusted by millions of businesses around the world.

Laravel: Laravel is a web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small things.

Firebase Web Phone authentication documentation

Advantages of validating phone numbers

  • It helps to ensure the phone number entered by the user is correct

  • Enforces the validation of the phone number used by the users

  • The platform is sure that the user can be reached via the phone number for notification or 2-factor-authentication codes

  • The proof of identity is important to the user to avoid impersonation

  • Enforces users and app security proof when combined with other authentication strategies

In a bit to get on board with exploring the features of using firebase phone authentication, let's start with a fresh laravel 9 app installation

laravel new laravel_firebase_phone_authentication

OR

composer create-project laravel/laravel_firebase_phone_authentication

After successful installation change the directory to laravel_firebase_phone_authentication

cd laravel_firebase_phone_authentication

--Run

php artisan serve

Next let's setup the firebase phone authentication here

image.png

Next, let's create a firebase project

image.png

The project is named as laravel-phone-no-verification

image.png

Next, click on continue

If you're using this for a real project enable the analytics for the project

image.png

But for this tutorial, we'll ignore enabling the analytics

image.png

Next, click on create project

image.png

Next, click on continue to access the project dashboard

image.png

Click on the web icon as shown in the previous image ....

Next, set the app name and click on the register app button

image.png

Next, click select the script tag to access the script for the integration to a web application

image.png

Then click on the continue to console.

Next, click on the authentication card

image.png

Click on get started

image.png

Next, click on the phone icon because for this application we'll be authenticating phone number

image.png

Next toggle the enable button to allow users to sign in with a mobile phone number, using Firebase SDK phone verification and user authentication tools.

image.png

Click on the Save button.

For more information about the firebase phone authentication

NOTE

Currently, there are two recommended web versions for authenticating users:

  • Web version 9 (modular) - we'll be using the modular approach in this article

  • Web version 8 (namespace)

image.png

It's recommended to use the npm but there is an Alternative setup to npm for web projects

Firebase web CDN libraries

For this tutorial we'll be using CDN libraries

https://www.gstatic.com/firebasejs/9.8.3/firebase-app.js

https://www.gstatic.com/firebasejs/9.8.3/firebase-auth.js

Next, Add and initialize the Authentication SDK

// TODO: Replace the following with your app's Firebase project configuration
// See: https://firebase.google.com/docs/web/learn-more#config-object
const firebaseConfig = {
  // ...
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);


// Initialize Firebase Authentication and get a reference to the service
const auth = getAuth(app);

Note: We'll be using the welcome.blade.php file for this tutorial demo with tailwindcss cdn

Let's update the script section of the

//jquery cdn library

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

//firebase modular script setup

<script type="module">

//import the initializeApp
    import {
        initializeApp
    } from "https://www.gstatic.com/firebasejs/9.8.3/firebase-app.js";

//import the getAuth, RecaptchaVerifier & signInWithPhoneNumber

  import {
        getAuth,
        RecaptchaVerifier,
        signInWithPhoneNumber
    } from 'https://www.gstatic.com/firebasejs/9.8.3/firebase-auth.js';


    //replace this section with the firebase config object from your firebase console
    const firebaseConfig = {
        apiKey: "",
        authDomain: "laravel-phone-no-verification.firebaseapp.com",
        projectId: "laravel-phone-no-verification",
        storageBucket: "laravel-phone-no-verification.appspot.com",
        messagingSenderId: "",
        appId: ""
    };

    //initialize firebase config
    const app = initializeApp(firebaseConfig);

//authenticate app communication to firebase
    const auth = getAuth(app);

//code update at the Recaptcha widget section

</script>

Next, set up the reCAPTCHA verifier

Before you can sign in users with their phone numbers, you must set up Firebase's reCAPTCHA verifier. Firebase uses reCAPTCHA to prevent abuse, such as by ensuring that the phone number verification request comes from one of your app's allowed domains.

You don't need to manually set up a reCAPTCHA client; when you use the Firebase SDK's RecaptchaVerifier object, Firebase automatically creates and handles any necessary client keys and secrets.

The RecaptchaVerifier object supports invisible reCAPTCHA, which can often verify the user without requiring any user action, as well as the reCAPTCHA widget, which always requires user interaction to complete successfully.

The underlying rendered reCAPTCHA can be localized to the user's preference by updating the language code on the Auth instance before rendering the reCAPTCHA. The aforementioned localization will also apply to the SMS message sent to the user, containing the verification code.

Note You can use this code to set the language on the Recaptcha

//english default
auth.languageCode = 'en';

//french 
auth.languageCode = 'fr';

The phone number verification has the Recaptcha verification in various forms

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
}, auth);
import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {}, auth);
import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
}, auth);
recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

After render resolves, you get the reCAPTCHA's widget ID, which you can use to make calls to the reCAPTCHA API:

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

In this tutorial, we'll use Using Recaptcha Widget

Remove the //code update at the Recaptcha section under the script tag and add this code below it.

    auth.languageCode = 'en';

//when the window loads render the Recaptcha
    window.onload = function() {
        render();
    };

    function render() {
        //   <div id="recaptcha-container" class="mb-4"></div>
        //recaptcha-container is an id of the place where you want to display the recaptcha
        window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {
            //size of the Recaptcha
            'size': 'normal',
            'callback': (response) => {
                //response from Recaptcha when successful

                //alert the user to enter a phone number
                alert('Recaptacha successful!!! Please enter your phone number.')

                //the send OTP button is enabled if it's successful
                $("#send_otp").removeAttr('disabled')
            },
            'expired-callback': () => {
                //notify the user that the Recaptcha has expired 
                alert('Recaptach expired!!! Please try again.')
            }
        }, auth);

        //render the Recaptcha
        recaptchaVerifier.render();
    }

image.png

Next, Send a verification code to the user's phone

To initiate phone number sign-in, we'll present the user with an interface that prompts them to provide their phone number, and then call signInWithPhoneNumber to request that Firebase send an authentication code to the user's phone by SMS:

  • Get the user's phone number.

Legal requirements vary, but as a best practice and to set expectations for your users, you should inform them that if they use phone sign-in, they might receive an SMS message for verification and standard rates apply.

  • Call signInWithPhoneNumber, passing to it the user's phone number and the RecaptchaVerifier you created earlier.

Implementation

Tailwindcss phone input code section update

<form class="w-full max-w-sm" style="display: block;" id="phone_input">
<div id="recaptcha-container" class="mb-4"></div>
<div class="flex items-center border-b border-teal-500 py-2">
<input id="phone_number" class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none" type="text" placeholder="Phone number" aria-label="Full name">
<button class="flex-shrink-0 bg-teal-500 hover:bg-teal-700 border-teal-500 hover:border-teal-700 text-sm border-4 text-white py-1 px-2 rounded" type="button" onclick="sendOTP();" disabled id="send_otp">
    Send OTP
</button>
</div>
</form>

When the user clicks on the send OTP button the sendOTP function is triggered

//in the script module type the function isn't accessed as usual except with window.sendOTP 

    window.sendOTP = function() {

        //get the user phone number
        var phoneNumber = $("#phone_number").val();

        //get the verified recaptcha
        const appVerifier = window.recaptchaVerifier;

        const auth = getAuth();

        //pass the auth, phoneNUmber and verifier to the signInWithPhoneNumber method
        signInWithPhoneNumber(auth, phoneNumber, appVerifier)
            .then((confirmationResult) => {
                //store the confirmation result
                window.confirmationResult = confirmationResult;

                // alert the user
                alert('Verification code sent!!! Please check your phone.')

                //show verification code input section and hide phone number section
                $("#verification_input").show();
                $("#phone_input").hide();

            }).catch((error) => {
                //If signInWithPhoneNumber results in an error, reset the reCAPTCHA so the user can try again:
                //reset the recaptcha if there's an error
                window.recaptchaVerifier.render().then(function(widgetId) {
                    grecaptcha.reset(widgetId);
                });
                //you can add the error message to the user interface
                alert(error.message)
            });
    }

image.png

The signInWithPhoneNumber method issues the reCAPTCHA challenge to the user, and if the user passes the challenge, requests that Firebase Authentication send an SMS message containing a verification code to the user's phone.

Firebase snippet web base

Sign in the user with the verification code

After the call to signInWithPhoneNumber succeeds, prompt the user to type the verification code they received by SMS. Then, sign in the user by passing the code to the confirm method of the ConfirmationResult object that was passed to signInWithPhoneNumber's fulfilment handler

Implementation

Taillwindcss verify code input section update

<form class="w-full max-w-sm" style="display: none;" id="verification_input">
<div class="flex items-center border-b border-teal-500 py-2">
<div id="recaptcha-container"></div>
<input id="verification_code" class="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none" type="text" placeholder="Enter OTP" aria-label="Verification code">
<button class="flex-shrink-0 bg-teal-500 hover:bg-teal-700 border-teal-500 hover:border-teal-700 text-sm border-4 text-white py-1 px-2 rounded" type="button" onclick="verifyOTP();">
    Verify OTP
</button>

<button class="flex-shrink-0 border-transparent border-4 text-teal-500 hover:text-teal-800 text-sm py-1 px-2 rounded" type="button" onclick="tryAgain();">
    Retry
</button>
</div>
</form>

The Verify OTP button will trigger the verifyOTP function

    window.verifyOTP = function() {
        //get the verification code entered by the user
        const code = $("#verification_code").val();

        confirmationResult.confirm(code).then((result) => {
            //if successful notify the user
            alert('Code verification successfull!!! Awesome!')
            const user = result.user;

            //hide the verification input section
            $("#verification_input").hide();
            $("#verification_code").val("");
            $("#phone_input").show();

            //you can do other stuff here as per your project requirements

        }).catch((error) => {
            //you can add the error message to the user interface
            alert(error.message)
        });
    }

The Retry again button will trigger the tryAgain function to show the phone input section

    window.tryAgain = function() {
        $("#verification_input").hide();
        $("#phone_input").show();
        $("#verification_code").val("");
    }

Debugging

If you see the error on the image below while testing

image.png

It means your domain isn't recognized on Firebase authorized domain.

Head over to Firebase Console -> Authentication -> sign-in-method -> Authorized Domains and add your domain.

image.png

Next steps

After a user signs in for the first time, a new user account is created and linked to the credentials—that is, the user name and password, phone number, or auth provider information—the user signed in with. This new account is stored as part of your Firebase project and can be used to identify a user across every app in your project, regardless of how the user signs in.

In your apps, the recommended way to know the auth status of your user is to set an observer on the Auth object. You can then get the user's basic profile information from the User object. See Manage Users.

In your Firebase Realtime Database and Cloud Storage Security Rules, you can get the signed-in user's unique user ID from the auth variable, and use it to control what data a user can access.

You can allow users to sign in to your app using multiple authentication providers by linking auth provider credentials to an existing user account.

To sign out a user, call signOut:

    window.signOut = function() {
        //import signOut
        const auth = getAuth();
        signOut(auth).then(() => {
            // Sign-out successful.
            alert('Sign-out successful')
        }).catch((error) => {
            // An error happened.
            alert(error.message)
        });
    }
  • Demo screenshot

Form display

image.png

Recaptcha successful

image.png

Verification code sent

image.png

OTP received

image.png

OTP verified successfully

image.png

image.png

Thank you for reading this article!!!.

If you find this article useful please kindly share it with your network and feel free to use the comment section for questions, answers, and contributions.

Did you find this article valuable?

Support Alemoh Rapheal Baja by becoming a sponsor. Any amount is appreciated!