Firebase Phone Auth
Firebase Phone Authentication verifies users by sending a one-time code to their mobile number via SMS. The user enters that code in your app, and Firebase confirms their identity. This method works especially well for mobile apps and regions where email accounts are less common.
How SMS Verification Works
Think of phone auth as a combination lock delivered by postal mail. You request the code (send a letter). The code arrives at the physical address (SMS to the phone). You enter the code (confirm you received it). The lock opens (Firebase grants access).
User enters phone number: +91 98765 43210
|
v
Firebase sends 6-digit OTP via SMS
|
v
User reads SMS and enters the code in your app
|
v
Firebase verifies the code
|
v
Valid? YES --> Creates or logs in user
Valid? NO --> Returns error (wrong code / expired)
Enabling Phone Auth in the Console
Go to Authentication > Sign-in method in the Firebase Console. Click Phone, toggle Enable on, and click Save. Phone auth is now active for your project.
Note: Phone authentication is available on the Blaze (pay-as-you-go) plan. The Spark (free) plan has limited SMS quotas for testing purposes. Each SMS verification costs a small amount in production, varying by country.
reCAPTCHA Verification
Phone auth requires a reCAPTCHA verification to prevent bots from abusing your SMS quota. Firebase handles reCAPTCHA automatically using a widget called RecaptchaVerifier. You need a visible button or container in your HTML for the reCAPTCHA widget to attach to.
<!-- The reCAPTCHA widget renders inside this button --> <button id="send-otp-btn">Send OTP</button> <input id="phone-input" type="tel" placeholder="+91XXXXXXXXXX" /> <input id="otp-input" type="text" placeholder="Enter OTP" /> <button id="verify-btn">Verify</button> <p id="phone-message"></p>
Step 1 — Setting Up RecaptchaVerifier
import {
RecaptchaVerifier,
signInWithPhoneNumber
} from "firebase/auth";
import { auth } from "./firebase";
let confirmationResult;
// Set up reCAPTCHA — run this when the page loads
function setupRecaptcha() {
window.recaptchaVerifier = new RecaptchaVerifier(
auth,
"send-otp-btn", // ID of the button element
{
size: "invisible", // or "normal" for a visible checkbox
callback: () => {
// reCAPTCHA solved — proceed with sending OTP
sendOTP();
}
}
);
}
setupRecaptcha();
The invisible size runs reCAPTCHA silently in the background. Most users never see a challenge. The normal size shows a checkbox that users must tick — useful as a fallback for high-risk environments.
Step 2 — Sending the OTP
async function sendOTP() {
const phoneNumber = document.getElementById("phone-input").value;
const appVerifier = window.recaptchaVerifier;
const message = document.getElementById("phone-message");
try {
confirmationResult = await signInWithPhoneNumber(
auth, phoneNumber, appVerifier
);
message.textContent = "OTP sent! Check your SMS.";
document.getElementById("verify-btn").style.display = "block";
} catch (error) {
message.textContent = "Error: " + error.message;
// Reset reCAPTCHA on failure
window.recaptchaVerifier.render().then((widgetId) => {
window.recaptchaVerifier.reset(widgetId);
});
}
}
document.getElementById("send-otp-btn").addEventListener("click", sendOTP);
Firebase sends the OTP to the number and returns a confirmationResult object. Store this object — you need it in the next step to verify the code the user enters.
Step 3 — Verifying the OTP
document.getElementById("verify-btn").addEventListener("click", async () => {
const otp = document.getElementById("otp-input").value;
const message = document.getElementById("phone-message");
try {
const result = await confirmationResult.confirm(otp);
const user = result.user;
message.textContent = "Verified! UID: " + user.uid;
} catch (error) {
if (error.code === "auth/invalid-verification-code") {
message.textContent = "Wrong code. Please try again.";
} else if (error.code === "auth/code-expired") {
message.textContent = "Code expired. Request a new one.";
} else {
message.textContent = "Verification failed: " + error.message;
}
}
});
Phone Number Format
Firebase requires phone numbers in E.164 international format: a plus sign, country code, and the number with no spaces or dashes.
Correct format examples: +919876543210 (India) +14155552671 (United States) +447911123456 (United Kingdom) Incorrect formats: 09876543210 (missing country code) +91 98765 43210 (spaces not allowed)
Validate and format the phone number before sending it to Firebase. You can use a library like libphonenumber-js to handle international formatting reliably.
Testing Phone Auth Without Real SMS
Firebase provides test phone numbers so you can develop and test without sending real SMS messages and incurring charges. Go to Authentication > Sign-in method > Phone and scroll to Phone numbers for testing.
Add a test number and a fixed test OTP. For example:
Test phone: +1 650-555-1234 Test OTP: 123456
When your app sends an OTP to this number, Firebase never sends a real SMS. It silently accepts the test OTP you defined. This saves money during development and speeds up testing.
Phone Auth Error Codes
auth/invalid-phone-number— the phone number format is wrongauth/too-many-requests— too many attempts from this number or deviceauth/quota-exceeded— SMS quota for the project is exhaustedauth/invalid-verification-code— the OTP entered is incorrectauth/code-expired— OTP validity period (5 minutes) has passed
Key Takeaway
Firebase Phone Authentication uses SMS OTPs to verify users in three steps: set up RecaptchaVerifier, call signInWithPhoneNumber to send the code, then call confirmationResult.confirm with the code the user enters. Always use international E.164 phone format. Set up test phone numbers in the console to avoid SMS charges during development.
