Demo Project to show how to do Phone Authentication in Flutter using Firebase backend.
At First | PhoneNo is entered and submitted |
---|---|
After OTP is entered & submitted | App is restarted |
---|---|
I felt there is no setp-by-step documentation for Firebase Phone Authentication in Flutter. There were couple of implementations on Medium but are out-dated and one article got it but that failed to explain some crucial concepts. AndroidX brought a lot of changes in addition to FlutterFire plugins update. I asked this question on stackoverflow almost 2 years ago, but failed to get step-by-step answer. So I created this demo project.
You can setup Firebase by following this guide: https://firebase.google.com/docs/flutter/setup
If you encounter errors with MultiDex
or AndroidX
make sure you follow below steps
// Inside android folder in app level build.gradle file
...
android {
...
defaultConfig {
...
multiDexEnabled true // add this
}
...
}
...
dependencies {
// implementation 'com.android.support:multidex:1.0.3' // No AndroidX support
implementation 'com.android.support:multidex:2.0.1' // Add this to support AndroidX
implementation 'androidx.browser:browser:1.2.0' // To display verification webpage in the user's default browser
...
}
...
- Ask for user's phoneNumber
- Get OTP from Firebase
- SignIn to Firebase
- SignIn/Login is done in the same way.
- The OTP is only used to get
AuthCrendential
object AuthCredential
object is the only thing that is used to signIn the user. It is obtained either fromverificationCompleted
callback function inverifyPhoneNumber
or from thePhoneAuthProvider
. (Don't worry if it's confusing, keep reading, you'll get it)
- User gives the
phoneNumber
- Firebase sends OTP
- SignIn the user
- If the SIM card with the
phoneNumber
is not in the device that is currently running the app,- We have to first ask the OTP and get
AuthCredential
object - Next we can use that
AuthCredential
to signIn This method works even if thephoneNumber
is in the device
- We have to first ask the OTP and get
- Else if user provided SIM phoneNumber is in the device running the app,
- We can signIn without the OTP.
- because the
verificationCompleted
callback fromsubmitPhoneNumber
function gives theAuthCredential
object which is needed to signIn the user - But in the previous case it ain't called because the SIM is not in the phone.
- If the SIM card with the
- SubmitPhoneNumber
Future<void> _submitPhoneNumber() async {
/// NOTE: Either append your phone number country code or add in the code itself
/// Since I'm in India we use "+91 " as prefix `phoneNumber`
String phoneNumber = "+91 " + _phoneNumberController.text.toString().trim();
print(phoneNumber);
/// The below functions are the callbacks, separated so as to make code more redable
void verificationCompleted(AuthCredential phoneAuthCredential) {
print('verificationCompleted');
...
this._phoneAuthCredential = phoneAuthCredential;
print(phoneAuthCredential);
}
void verificationFailed(AuthException error) {
...
print(error);
}
void codeSent(String verificationId, [int code]) {
...
print('codeSent');
}
void codeAutoRetrievalTimeout(String verificationId) {
...
print('codeAutoRetrievalTimeout');
}
await FirebaseAuth.instance.verifyPhoneNumber(
/// Make sure to prefix with your country code
phoneNumber: phoneNumber,
/// `seconds` didn't work. The underlying implementation code only reads in `millisenconds`
timeout: Duration(milliseconds: 10000),
/// If the SIM (with phoneNumber) is in the current device this function is called.
/// This function gives `AuthCredential`. Moreover `login` function can be called from this callback
verificationCompleted: verificationCompleted,
/// Called when the verification is failed
verificationFailed: verificationFailed,
/// This is called after the OTP is sent. Gives a `verificationId` and `code`
codeSent: codeSent,
/// After automatic code retrival `tmeout` this function is called
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout,
); // All the callbacks are above
}
- SubmitOTP
void _submitOTP() {
/// get the `smsCode` from the user
String smsCode = _otpController.text.toString().trim();
/// when used different phoneNumber other than the current (running) device
/// we need to use OTP to get `phoneAuthCredential` which is inturn used to signIn/login
this._phoneAuthCredential = PhoneAuthProvider.getCredential(
verificationId: this._verificationId, smsCode: smsCode);
_login();
}
- SignIn/LogIn
Future<void> _login() async {
/// This method is used to login the user
/// `AuthCredential`(`_phoneAuthCredential`) is needed for the signIn method
/// After the signIn method from `AuthResult` we can get `FirebaserUser`(`_firebaseUser`)
try {
await FirebaseAuth.instance
.signInWithCredential(this._phoneAuthCredential)
.then((AuthResult authRes) {
_firebaseUser = authRes.user;
print(_firebaseUser.toString());
});
...
} catch (e) {
...
print(e.toString());
}
}
- Logout
Future<void> _logout() async {
/// Method to Logout the `FirebaseUser` (`_firebaseUser`)
try {
// signout code
await FirebaseAuth.instance.signOut();
_firebaseUser = null;
...
} catch (e) {
...
print(e.toString());
}
}
For more details on implementation please refer to the lib/main.dart
file.
- Please feel free to contribute to this README (Pull Requests) and this stackoverflow answer
- If you find this
README
useful please star the repository