🔥 Firebase OTP (Sign In with Phone) using Webviewer

There have been several requests for this in the past year, but I have not seen a solution. Here, then, is one method to allow a user to sign in to Firebase (or if you want, to just authenticate their phone number).

The method uses an html page and javascript, which allows for the use of a recaptcha in order to generate the verification code and send an SMS. I understand that Firebase allows for 10,000 free SMS per month (needs confirming under current requirements)

I found the solution on medium.com here:

Firebase Phone Authentication

and modified the html/css/code to interact with App Inventor (webviewstring)

I am not sure for how long Firebase will continue to provide version 8 SDK links in the current format, because it is heavily pushing its tree-shaking version 9, but for now, this will work for our App Inventor apps.

I have put together a simple app that loads the html; the user enters their phone number, with + sign and country code, then the user completes the recaptcha, then the device receives an SMS with the verification code. The user copies and pastes the code to the html page, and sends the code. Once verified, the user is signed in and firebase returns the userData which includes the UID, the refreshToken and the accessToken, these can then be used to manage a users future access.

Security concerns
Authentication using only a phone number, while convenient, is less secure than the other available methods, because possession of a phone number can be easily transferred between users. Also, on devices with multiple user profiles, any user that can receive SMS messages can sign in to an account using the device's phone number.

If you use phone number based sign-in in your app, you should offer it alongside more secure sign-in methods, and inform users of the security tradeoffs of using phone number sign-in.

BLOCKS

SCREENS

HTML
(you need to add your own Firebase project's firebaseConfig information)

<!DOCTYPE html>
<!--https://medium.com/front-end-weekly/firebase-phone-authentication-web-tutorial-2019-29f5f5c97839-->
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>OTP</title>
    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
  </head>
  <body>
	  
    <div id="holder"  style="max-width:240px;margin: auto;">
		<div id="done"></div>
    <h2>OTP Sign Up</h2>
    <!-- Add two inputs for "phoneNumber" and "code" -->
    <!-- Add two buttons to submit the inputs -->
    Phone Number:<br>
    <input type="tel" id="phoneNumber" class="w3-input w3-border w3-round-large" style="width:200px" /><br>
    <button id="sign-in-button" onclick="submitPhoneNumberAuth()" class="w3-btn w3-ripple w3-blue w3-round-large" style="width:200px">
      SIGN IN WITH PHONE
    </button><br><br><br>

    <!-- Add a container for reCaptcha -->
    <div id="recaptcha-container"></div><br><br>

    OTP Code:<br>
    <input type="text" id="code" class="w3-input w3-border w3-round-large" style="width:200px" /><br>
    <button id="confirm-code" onclick="submitPhoneNumberAuthCode()" class="w3-btn w3-ripple w3-blue w3-round-large" style="width:200px">
      ENTER CODE
    </button>
    <p id="notes" style="max-width:200px;word-wrap: break-word;">1. Enter phone number with + and country code, then click Sign In with Phone<br>2. Complete the recaptcha 3. Get the OTP code from your SMS and type/paste it in, then click Enter Code</p>
    </div>
    <!-- Add the latest firebase dependecies from CDN -->
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-auth.js"></script>

    <script>
      // Place your config here
      var firebaseConfig = {
        apiKey: "",
        authDomain: "",
        databaseURL: "",
        projectId: "",
        storageBucket: "",
        messagingSenderId: "",
        appId: ""
      };

      firebase.initializeApp(firebaseConfig);

      // Create a Recaptcha verifier instance globally
      // Calls submitPhoneNumberAuth() when the captcha is verified
      window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
        "recaptcha-container",
        {
          size: "invisible",
          callback: function(response) {
            submitPhoneNumberAuth();
          }
        }
      );

      // This function runs when the 'sign-in-button' is clicked
      // Takes the value from the 'phoneNumber' input and sends SMS to that phone number
      function submitPhoneNumberAuth() {
        var phoneNumber = document.getElementById("phoneNumber").value;
        var appVerifier = window.recaptchaVerifier;
        firebase
          .auth()
          .signInWithPhoneNumber(phoneNumber, appVerifier)
          .then(function(confirmationResult) {
            window.confirmationResult = confirmationResult;
          })
          .catch(function(error) {
            console.log(error);
          });
      }

      // This function runs when the 'confirm-code' button is clicked
      // Takes the value from the 'code' input and submits the code to verify the phone number
      // Return a user object if the authentication was successful, and auth is complete
      function submitPhoneNumberAuthCode() {
        var code = document.getElementById("code").value;
        confirmationResult
          .confirm(code)
          .then(function(result) {
            var user = result.user;
            //console.log(user);
            document.getElementById("done").innerHTML = "OTP completed";
            window.AppInventor.setWebViewString(JSON.stringify(user));
          })
          .catch(function(error) {
            console.log(error);
            document.getElementById("done").innerHTML = error;
          });
      }

      //This function runs everytime the auth state changes. Use to verify if the user is logged in
      firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
          console.log("USER LOGGED IN");
        } else {
          // No user is signed in.
          console.log("USER NOT LOGGED IN");
        }
      });
    </script>
  </body>
</html>

Note this guide has been updated, a small change to the html, exchanging the word normal for invisible in the recaptchaVerifier section.

10 Likes

I've tried it and it works. Please help me how to get OTP automatically without having to enter a phone number like this?

If there is a method/extension that can get the phone number from the device, you could use that to automate further, edit the html to run the phone number across with webviewstring.