I have searched many websites and I didn't find a way to implement phone authentication in Flutter using Firebase. Can anyone tell me how to this?
-
You could mimic firebase.google.com/docs/auth/web/phone-auth or checkout github.com/flutter/flutter/issues/10404 which links to github.com/flutter/plugins/tree/master/packages/firebase_auth (lmgtfy: phone authentication flutter)Clemens Tolboom– Clemens Tolboom2018-05-04 19:41:58 +00:00Commented May 4, 2018 at 19:41
-
I have implemented the phone auth on Node.js, but stuck at right there. Do you have any advice for using web phone auth as a WebView on Flutter? For example, how can a Flutter app know that the user is logged in or not after authorized by phone auth?Sodbileg Gansukh– Sodbileg Gansukh2018-05-16 05:39:15 +00:00Commented May 16, 2018 at 5:39
-
Please find the answer to this question below.Mohith7548– Mohith75482020-10-19 02:41:45 +00:00Commented Oct 19, 2020 at 2:41
6 Answers
Well Documented Working Demo project here
Below is the detailed procedure
Steps
- Ask for user's phoneNumber
- Get OTP from Firebase
- SignIn to Firebase
Rules
- SignIn/Login is done in the same way.
- The OTP is only used to get
AuthCrendentialobject AuthCredentialobject is the only thing that is used to signIn the user. It is obtained either fromverificationCompletedcallback function inverifyPhoneNumberor from thePhoneAuthProvider.
(Don't worry if it's confusing, keep reading, you'll get it)
Workflow
- User gives the
phoneNumber - Firebase sends OTP
- SignIn the user
- If the SIM card with the
phoneNumberis not in the device that is currently running the app,- We have to first ask the OTP and get
AuthCredentialobject - Next we can use that
AuthCredentialto signIn This method works even if thephoneNumberis 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
verificationCompletedcallback fromsubmitPhoneNumberfunction gives theAuthCredentialobject 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
Functions
- 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 readable
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 `milliseconds`
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 here.
If you found issues, edits are welcome to this answer and to this repo README
4 Comments
Currently _signInPhoneNumber is deprecated, so use this:
try {
AuthCredentialauthCredential = PhoneAuthProvider.getCredential(verificationId: verificationId, verificationsCode: smsCode);
await _firebaseAuth
.signInWithCredential(authCredential)
.then((FirebaseUser user) async {
final FirebaseUser currentUser = await _firebaseAuth.currentUser();
assert(user.uid == currentUser.uid);
print('signed in with phone number successful: user -> $user');
}
}
Comments
Below are the steps:-
Get OTP based on Phone Number:-
void sendOTP(String phoneNumber, PhoneCodeSent codeSent, PhoneVerificationFailed verificationFailed) { if (!phoneNumber.contains('+')) phoneNumber = '+91' + phoneNumber; _firebaseAuth.verifyPhoneNumber( phoneNumber: phoneNumber, timeout: Duration(seconds: 30), verificationCompleted: null, verificationFailed: verificationFailed, codeSent: codeSent, codeAutoRetrievalTimeout: null); }Use the codeSent function to retrieve verification_id and pass it to OTP screen
void codeSent(String verificationId, [int forceResendingToken]) { Navigator.push( context, MaterialPageRoute( builder: (context) => Otp( phoneNumber: _phoneNumber, verificationId: verificationId, ))); }Get user based on verification_id and OTP
Future<bool> verifyOTP(String verificationId, String otp) async { AuthCredential credential = PhoneAuthProvider.getCredential( verificationId: verificationId, smsCode: otp, ); AuthResult result; try { result = await _firebaseAuth.signInWithCredential(credential); } catch (e) { // throw e; return false; } print(result); (await result.user.getIdToken()).claims.forEach((k, v) { print('k= $k and v= $v'); }); if (result.user.uid != null) return true; return false; }
For more details watch the below video
Comments
I had the same issue but I was building an Ionic app.
you can do firebase phone auth on the web. the idea is:
- take the user's phone number and send to a webpage.
create a recaptchaVerifier
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');sign in the user with phone number:
firebase.auth().signInWithPhoneNumber(phoneNumber, recaptchaVerifier) .then(confirmationResult => { myVerificationId = confirmationResult.verificationId; }) .catch(error => { console.log('error', error); })send the confirmation id back to the flutter app through a deeplink
Firebase will send the sms code.
sign in the user with any method that takes the confirmation Id and the code as parameters. for the web it goes like this:
let signinCredintial = firebase.auth.PhoneAuthProvider.credential(this.verificationId, this.code); firebase.auth().signInWithCredential(signinCredintial) .then(response => { // user is signed in })
1 Comment
I have implemented the phone auth singnIn with firebase in flutter its quite easy just import the firebase_auth library and validate the phone number is in proper format i.e it has a "+" sign in the beginning followed by country code then the phone number then the code goes like this
if (phoneExp.hasMatch(phon))
{
final PhoneVerificationCompleted verificationCompleted=(FirebaseUser user){
setState(() {
_message=Future<String>.value("auto sign in succedded $user");
debugPrint("Sign up succedded");
_pref.setString("phonkey",user.phoneNumber.toString());
MyNavigator.goToDetail(context);
//called when the otp is variefied automatically
});
};
final PhoneVerificationFailed verificationFailed=(AuthException authException){
setState(() {
_message=Future<String>.value("verification failed code: ${authException.code}. Message: ${authException.message}");
});
};
final PhoneCodeSent codeSent=(String verificationId,[int forceResendingToken]) async {
this.verificationId=verificationId;
};
final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout = (String verificationId){
this.verificationId=verificationId;
};
await _auth.verifyPhoneNumber(
phoneNumber: phon,
timeout: Duration(seconds: 60),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout
);
}
and if the phone wasn't able to detect the otp sent automatically, get the otp in a string and implement this function
void _signInWithOtp() async{
final FirebaseUser user = await _auth.signInWithPhoneNumber(
verificationId: verificationId,
smsCode: _otpController.text,
);
Comments
Use the flutter_otp package to send SMS with OTP easily. The advantages are:
- You can send custom OTP messages.
- OTP can be generated in any range.
Example of using it :
import 'package:flutter_otp/flutter_otp.dart';
...
FlutterOtp myOtpObj = FlutterOtp();
myOtpObj.sendOtp('7975235555');
...
// you can check as follows
bool correctOrNot = myOtpObj.resultChecker(<OTP entered by user>);
Check out the flutter_otp repository here