Firebase Authentication using a Phone Number

Junaid S. Shaikh
Sep 5, 2018 · 5 min read

Introduction to Firebase Authentication

Firebase is a secure and real-time database for Mobile (Android & iOS) and Web applications. Firebase offers backend services for your application. It provides authentication using password, phone numbers, Google, Facebook and Twitter and more. You may have seen Phone number authentication in many apps. You can use Firebase to sign in a user by sending SMS message i.e. OTP to the user’s phone.

Benefits of Phone number Authentication:

a) Authenticate identity: Phone verification helps to authenticate identity of user.

b) Prohibiting dummy users: Phone number authentication prevents duplication of accounts.

Why Phone number Authentication:

Firebase provides phone number authentication for free up to 10,000 SMS verification per month. It is enough for starter apps.

Before wasting a time let’s begin with Tutorial.

activity_mobile.xml

<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android"
xmlns:app=”http://schemas.android.com/apk/res-auto"
xmlns:tools=”http://schemas.android.com/tools"
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”.LoginActivity”>

<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginTop=”64dp”
android:orientation=”vertical”
android:padding=”16dp”>

<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:orientation=”horizontal”>

<Spinner
android:id=”@+id/mobile_country”
android:layout_width=”96dp”
android:layout_height=”56dp”
style=”@style/Base.Widget.AppCompat.Spinner.Underlined”
android:entries=”@array/str_array_country_code”/>

<EditText
android:id=”@+id/mobile_number”
android:layout_width=”match_parent”
android:layout_height=”56dp”
android:hint=”@string/str_mobile”
android:inputType=”phone”
android:textSize=”16sp”
android:maxLength=”10"/>

</LinearLayout>

<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginTop=”8dp”
android:orientation=”vertical”>

<TextView
android:id=”@+id/mobile_otp_message”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:text=”@string/str_otp_text”
android:textSize=”16sp”
android:layout_marginBottom=”8dp”
android:visibility=”gone”/>

<EditText
android:id=”@+id/mobile_code”
android:layout_width=”match_parent”
android:layout_height=”56dp”
android:hint=”@string/str_verification_code”
android:inputType=”number”
android:textSize=”16sp”
android:maxLength=”6"
android:textAlignment=”center”
android:visibility=”gone”/>

</LinearLayout>


</LinearLayout>

<Button
android:id=”@+id/mobile_code_button”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:textAllCaps=”false”
android:text=”@string/str_button_next”
style=”@style/Widget.AppCompat.Button.Colored”
android:layout_alignParentBottom=”true”
android:layout_marginLeft=”24dp”
android:layout_marginRight=”24dp”/>

<Button
android:id=”@+id/mobile_login_button”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:textAllCaps=”false”
android:text=”@string/str_button_verify”
style=”@style/Widget.AppCompat.Button.Colored”
android:layout_alignParentBottom=”true”
android:layout_marginLeft=”24dp”
android:layout_marginRight=”24dp”
android:visibility=”gone”/>

</RelativeLayout>

LoginActivity.java

  1. How to send verification on User’s phone number

private void sendVerificationNumber(String mMobileNumber) {

PhoneAuthProvider.getInstance().verifyPhoneNumber(

mMobileNumber, // Phone number to verify with coutry code

60, // Timeout duration

TimeUnit.SECONDS, // Unit of timeout

this, // Activity (for callback binding)

mCallbacks); // OnVerificationStateChangedCallbacks

}

verifyPhoneNumber() method is used to send verification code to the user.

2) Verification callbacks

mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
}

@Override
public void onVerificationFailed(FirebaseException e) {

}

@Override
public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) {

mVerificationId = verificationId;
mResendToken = token;

}
};

- onVerificationCompleted(PhoneAuthCredential phoneAuthCredential)

This callback will be invoked in two situations:

1 — Instant verification. In some cases, the phone number can be instant without needing to send or enter a verification code.

2 — Auto-retrieval. Some devices using Google Play services can automatically detect the incoming verification SMS and perform verification without user action.

- onVerificationFailed(FirebaseException e)

This callback is invoked in an invalid request for verification is made, for instance, if the phone number format is not valid.

- onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token)

The SMS verification code has been sent to the provided phone number, we now need to ask the user to enter the code and then construct a credential by combining the code with a verification ID.

3) PhoneAuthCredential object

PhoneAuthCredential credential = PhoneAuthProvider.getCredential(mVerificationId, mCode);

After the user enters the verification code received from Firebase to user’s phone, a PhoneAuthCredential object is created by using verification code and verification ID that passed to the onCodeSent() callback method.

Sign In user

private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser currentUser = mAuth.getCurrentUser();
String userId = currentUser.getUid();

// Sign in success, update the UI

} else {
// Sign in failed, display a message and update the UI
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
}
}
}
});
}

After you get a PhoneAuthCredential object, complete the sign in by passing an object to FirebaseAuth.signInWithCredential.

LoginActivity.java detail code

public class LoginActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

private Spinner mCountrySpinner;
private EditText mMobileNumberText;
private EditText mVerificationCodeText;
private Button mGetCodeButton;
private Button mSignInButton;
private ProgressDialog mProgressDialog;
private TextView mMessageTextView;

private DatabaseReference mDatabase;

private String mVerificationId;

private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks;
private PhoneAuthProvider.ForceResendingToken mResendToken;
private FirebaseAuth mAuth;

private String mCountryCode;
private String mMobileNumber;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

mCountrySpinner = findViewById(R.id.mobile_country);
mMobileNumberText = findViewById(R.id.mobile_number);
mVerificationCodeText = findViewById(R.id.mobile_code);
mGetCodeButton = findViewById(R.id.mobile_code_button);
mSignInButton = findViewById(R.id.mobile_login_button);
mMessageTextView = findViewById(R.id.mobile_otp_message);
mProgressDialog = new ProgressDialog(this);
mAuth = FirebaseAuth.getInstance();

mCountrySpinner.setOnItemSelectedListener(this);

mGetCodeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String mobile_number = mMobileNumberText.getText().toString();
checkMobileNumber(mobile_number);
}
});


mSignInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String mCode = mVerificationCodeText.getText().toString();
PhoneAuthCredential mAuthCredential = PhoneAuthProvider.getCredential(mVerificationId, mCode);
signInWithPhoneAuthCredential(mAuthCredential);
}
});

mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
}

@Override
public void onVerificationFailed(FirebaseException e) {

}

@Override
public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) {

mVerificationId = verificationId;
mResendToken = token;

mMobileNumberText.setEnabled(false);

mVerificationCodeText.setVisibility(View.VISIBLE);
mMessageTextView.setVisibility(View.VISIBLE);

mGetCodeButton.setVisibility(View.GONE);
mSignInButton.setVisibility(View.VISIBLE);

mProgressDialog.dismiss();

}
};

}

private void checkMobileNumber(String mobile_number) {
if(mCountryCode.isEmpty()) {
Toast.makeText(LoginActivity.this, “Please select Country code”, Toast.LENGTH_SHORT).show();
} else if(mobile_number.isEmpty() || mobile_number.length() < 10) {
mMobileNumberText.setError(“Mobile number is required of 10 digits.”);
} else {
mMobileNumber = mCountryCode+””+mobile_number;
sendVerificationNumber(mMobileNumber);
}
}

private void sendVerificationNumber(String mMobileNumber) {
mProgressDialog.setMessage(“Please wait a moment”);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
PhoneAuthProvider.getInstance().verifyPhoneNumber(mMobileNumber, 60, TimeUnit.SECONDS, this, mCallbacks);
}

private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mProgressDialog.setMessage(“Please wait a moment”);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser currentUser = mAuth.getCurrentUser();
assert currentUser != null;
final String userId = currentUser.getUid();

mDatabase = FirebaseDatabase.getInstance().getReference().child(“user_info”).child(userId);

Map<String, Object> userMap = new HashMap<>();
userMap.put(“user_mobile”, mMobileNumber);
userMap.put(“timestamp”, ServerValue.TIMESTAMP);

mDatabase.updateChildren(userMap, new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if(databaseError == null) {
mProgressDialog.dismiss();

Intent businessIntent = new Intent(LoginActivity.this, MainActivity.class);
businessIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(businessIntent);
finish();
mProgressDialog.dismiss();

} else {
mProgressDialog.dismiss();
Toast.makeText(LoginActivity.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});

} else {

if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
}
mProgressDialog.dismiss();
}
}
});
}

@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mCountryCode = String.valueOf(mCountrySpinner.getSelectedItem());
}

@Override
public void onNothingSelected(AdapterView<?> adapterView) {

}
}

MainActivity.java

activity_main.xml

public class MainActivity extends AppCompatActivity {

private FirebaseAuth mAuth;
private FirebaseUser mUser;
private DatabaseReference mUserDatabase;
private DatabaseReference mRootDatabase;

private String mCurrentUserId;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mAuth = FirebaseAuth.getInstance();
if(mAuth != null) {
mUser = mAuth.getCurrentUser();
if (mUser != null) {
mCurrentUserId = mUser.getUid();

mRootDatabase = FirebaseDatabase.getInstance().getReference();
mUserDatabase = mRootDatabase.child(“user_info”).child(mCurrentUserId);

} else {
sendToStart();
}
}

}

@Override
public void onStart() {
super.onStart();
FirebaseUser currentUser = mAuth.getCurrentUser();

if(currentUser == null) {
sendToStart();
}
}

private void sendToStart() {
Intent startIntent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(startIntent);
finish();
}
}

Junaid S. Shaikh

Written by

I am working in Android and web development since last 2 years.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade