I am new to flutter web. I have implemented firebase login functionality in my flutter web application. This functionality works correctly in local. But When i deploy the website on my own server, if i enter correct credentials, it works correctly on live, but whenever i enter wrong password, at that time it gives me exception,
Uncaught ReferenceError: Toastify is not defined
I have used fluttertoast library to dispaly toast messages, i m not sure what is causing the issue, is this error related to toast message or related to firebase. Please see attached screenshot of error
Is this issue related to fluttertoast library or related to firebase? How to resolve this issue, do we need to do any configuration related to domain in firebase?
I am using following code to signin User
Future<void> _signInWithEmailPassword() async {
UtilityHelper.showToast(message: "Login clicked");
_formkey.currentState?.save();
bool _isValid = _formkey.currentState?.validate() ?? false;
FocusScope.of(context).requestFocus(FocusNode());
if (_isValid) {
setState(() {
_loginType = LoginType.normal;
_isLoading = true;
});
final authProvider = Provider.of<AuthProvider>(context, listen: false);
final hasResponse = await authProvider.singInUser(loginReqModel);
redirectToHome(hasResponse, authProvider);
}
}
late UserModel _user;
UserModel get user => _user;
bool get isChangePasswordButtonShown =>
_authRepo.isUserLoggedInUsingPasssword;
String errorMsg = '';
Future<bool> singInUser(LoginReqModel reqModel) async {
try {
final response = await _authRepo.singInUser(reqModel);
if (response != null) {
_user = response;
notifyListeners();
return true;
}
notifyListeners();
return false;
} catch (error) {
print(error);
errorMsg = UtilityHelper.getErrorMessage(error);
return false;
}
}
Any help would be appreciated.
This issue was related to flutter toast library that i was using to display toast message, it did not worked with live domain.
So replacing that library with oktoast library solved the issue
Related
I'm trying to refactor my code to reduce Firebase read operations. For this I'm using Sharedpreferences. The code is structured in such a way that there's a provider that take's care of the update process and saves the new values in shared preferences. Here is the code.
submit() async {
final User user = _auth.currentUser;
DocumentReference ref =
FirebaseFirestore.instance.collection('users').doc(user.uid);
final prefs = await SharedPreferences.getInstance();
try {
if (_image != null){
mediaurl= await uploadImage();
await ref.update({"MediaURL": mediaurl});
prefs.setString("MediaURL", mediaurl);
}
if(username!=null){
ref.update({"username":userNamecontroller.text});
prefs.setString('username', username);
}
if(description!=null){
ref.update({"description":descriptionController.text});
prefs.setString('description', description);
}
} catch (e) {print("tHE ERROR IS $e");}
notifyListeners();
}
The problem however is the submit function does not work. No data is updated to firebase and the error from my catch block is
tHE ERROR IS NoSuchMethodError: The getter 'absolute' was called on null.
Any ideas what this 'absolute' is?
I am working in Xamarin forms application.
I am using below code snippet to get token for AAD sign-in.
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync().ConfigureAwait(false);
try
{
if (btnSignInSignOut.Text == "Sign in")
{
try
{
IAccount firstAccount = accounts.FirstOrDefault();
authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
.ExecuteAsync()
.ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
try
{
var builder = App.PCA.AcquireTokenInteractive(App.Scopes)
.WithParentActivityOrWindow(App.ParentWindow);
if (Device.RuntimePlatform != "UWP")
{
// on Android and iOS, prefer to use the system browser, which does not exist on UWP
SystemWebViewOptions systemWebViewOptions = new SystemWebViewOptions()
{
iOSHidePrivacyPrompt = true,
};
builder.WithSystemWebViewOptions(systemWebViewOptions);
builder.WithUseEmbeddedWebView(false);
}
authResult = await builder.ExecuteAsync().ConfigureAwait(false);
}
catch (Exception ex2)
{
await DisplayAlert("Acquire token interactive failed. See exception message for details: ", ex2.Message, "Dismiss");
}
}
if (authResult != null)
{
var content = await GetHttpContentWithTokenAsync(authResult.AccessToken);
UpdateUserContent(content);
}
}
else
{
while (accounts.Any())
{
await App.PCA.RemoveAsync(accounts.FirstOrDefault()).ConfigureAwait(false);
accounts = await App.PCA.GetAccountsAsync().ConfigureAwait(false);
}
Device.BeginInvokeOnMainThread(() =>
{
slUser.IsVisible = false;
btnSignInSignOut.Text = "Sign in";
});
}
}
catch (Exception ex)
{
await DisplayAlert("Authentication failed. See exception message for details: ", ex.Message, "Dismiss");
}
But after some time, token expires somehow and not refresh. Due to that it always redirect user to MS login page.
My requirement is, It should automatically take the logged in user's details.
You can take reference from this code.
I have also check other options like to directly call api to get refresh token but didn't found anything helpful.
Let me know if anyone have any idea about it.
Thanks in Advance.
For now, MSAL already caches your authorization and can log you in silently if it’s still valid. So, as a user, you don’t need to sign in every time you use the app.
You could use SecureStorage.SetAsync to store the access token.
Sign-in:
public async Task<bool> SignInAsync()
{
try
{
var accounts = await _pca.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
var authResult = await _pca.AcquireTokenSilent(Scopes, firstAccount).ExecuteAsync();
// Store the access token securely for later use.
await SecureStorage.SetAsync("AccessToken", authResult?.AccessToken);
return true;
}
catch (MsalUiRequiredException)
{
try
{
// This means we need to login again through the MSAL window.
var authResult = await _pca.AcquireTokenInteractive(Scopes)
.WithParentActivityOrWindow(ParentWindow)
.ExecuteAsync();
// Store the access token securely for later use.
await SecureStorage.SetAsync("AccessToken", authResult?.AccessToken);
return true;
}
catch (Exception ex2)
{
Debug.WriteLine(ex2.ToString());
return false;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return false;
}
}
Just for clarification, MSAL does not return, issue the token, and does not expire the token. When your token expireS then MSAL will automatically refresh your token when calling the AcquireTokenSilentAsync (so you don't have to refresh your token). The reason why your application is redirecting to the login page is because when you call the authenticated API then this API is returning the response 401 (Unauthorized) which means while calling the API you are not sending the token with the request. In return when the server returns 401 (Unauthorized) response, then your application is redirecting the user to the login page.
Read more about MSAL token expiration here.
Update your code accordingly:
await SecureStorage.SetAsync("accessToken", authResult.AccessToken);
My app workes with Firebase and Flutter. When reload() is launched, I get this error :
"No implementation found for method User#reload on channel plugins.flutter.io/firebase_auth"
All other firebase functions work, multidexEnabled is true
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
Method :
Future<bool> reloadFirebase({required BuildContext context}) async {
bool _isUserStillConnected = true;
try {
await _firebaseAuth.currentUser?.reload();
User? _user = currentUser;
if(_user == null) {
_isUserStillConnected = false;
showDisconnectedDialog(context: context);
}
} on FirebaseAuthException catch(e) {
_isUserStillConnected = false;
showDisconnectedDialog(context: context);
}
return _isUserStillConnected;
}
call :
ListTile(
onTap: () async {
bool _isUserStillConnected = await AuthenticationProvider().reloadFirebase(context: context);
if(_isUserStillConnected) {
Navigator.of(context).pushNamed(
PAGE_ROOM,
arguments: _roomModels[index],
);
}
},
The error suggests that something went wrong with the authentication, so please try the following possible solutions:
Make sure that you have properly set up the sign-up method in the authentication tab of your firebase console
Depending on your FB version in yaml file, make sure to import firebase_core
Check for plugin conflicts / try to use the latest versions from pub.dev
If it has to do something with the reload() function, maybe try the solution from here, as it might be better for your case: https://stackoverflow.com/a/64899979/15117201
So i am making a simple sign up and login screens in flutter application that uses phone authentication of firebase. For sign up im able to register new user, as the user provides his phone number and gets OTP. But for login i wanna check if the entered number is already registered. If so he gets otp and logs in or if not registered then asks to sign up first.
Firebase admin SDK supports this. Here's how to set up firebase admin (documentation). After you set up admin, you can use cloud_functions package to call APIs from the firebase admin SDK and the API we'll be using is one that allows us to get a user by phone number (documentation). If the API response is a user record, we know a phone exists.
In this example, I'm using node.js. In functions/index.js:
exports.checkIfPhoneExists = functions.https.onCall((data, context) => {
const phone = data.phone
return admin.auth().getUserByPhoneNumber(phone)
.then(function(userRecord){
return true;
})
.catch(function(error) {
return false;
});
});
In your dart code:
final HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(functionName: 'checkIfPhoneExists');
dynamic resp = await callable.call({'phone': _phone});
if (resp.data) {
// user exists
}
Once the OTP is sent to the user you can verify if the user is a new user or an existing one in verify OTP function
verifyOtp(String input, context) async {
String retVal = "error";
OurUser _user = OurUser();
print(input);
final AuthCredential credential = PhoneAuthProvider.credential(
verificationId: _verificationId, smsCode: input);
try {
// await _auth.signInWithCredential(credential);
UserCredential _authResult = await _auth.signInWithCredential(credential);
// Here i have to save the details of the user in the database
if (_authResult.additionalUserInfo.isNewUser) {
currentUser.uid = _authResult.user.uid;
currentUser.phone = _inputText;
currentUser.type = "Customer";
retVal = await OurDatabase().createUser(currentUser);
} else {
// get the information of the user from the database this already exists
currentUser = await OurDatabase().getUserInfo(_authResult.user.uid);
if(currentUser!= null) {
Navigator.pushNamedAndRemoveUntil(
context, "/homescreen", (route) => false);
}
}
print("End of the await");
// when signup with the otp
if (retVal == "success") {
print("why not inside this mane");
Navigator.pushNamedAndRemoveUntil(
context, "/homescreen", (route) => false);
}
saveAllData();
} catch (e) {
print(e);
print("Something went wrong");
//prin
}
}
Now this is when you want to verify OTP from the user and after the top is verified you can know if the user was indeed a new user or an old one but what if you wanted to know that beforehand then the best possible solution would be to create a new collection in the firestore that would have only one document(so you are charged only for one document read) that would just contain all the numbers of the users that are registered within your application,
I used a simple straight forward way and it worked just fine.
First, add the mobile number to the firebase database in a separate node when the user creates the account.
await dbref.child("RegisteredNumbers").push().set({
"phoneNo": FirebaseAuth.instance.currentUser!.phoneNumber,
});
whenever a user tries to log in or signup check in this node if the provided number is available in It or not.
Future<bool> checkNumberIsRegistered({required String number}) async {
bool isNumberRegistered = false;
try {
await dbref.child("RegisteredNumbers").once().then((data) {
for (var i in data.snapshot.children) {
String data = i.child("phoneNo").value.toString();
if (number == data) {
isNumberRegistered = true;
return isNumberRegistered;
} else {
isNumberRegistered = false;
}
}
});
return isNumberRegistered;
} catch (e) {
return false;
}
}
Hope it helps
My goal for this app is to have persistent log in, so that the user of my Flutter app needs to sign in only once (unless they sign out) and whenever my Flutter app restarts, they do not need to log back in. I saw many examples with using Firebase Authentication and the .currentUser() method, but I am still having to log in every time I restart the app. I have tested this on the simulator (ios) and on my physical iphone while running debug mode on xCode (usb connection). Is it possible that I cannot test this functionality this way? Because I do see a message pop up on both android studio and xCode terminals that mention lost connection to device or stopped running because of the restarting. If that's the case, how can I test that persistent log in is working?
If that isn't the case, what am I doing wrong?? I've included the code below. This is happening within a stateful widget, of course.
final _auth = FirebaseAuth.instance;
checkIfCurrentUserExists() async {
try {
await _auth.currentUser().then((user) {
print('this is the user $user');
if (user != null && user.email != null) {
userIsLoggedIn = true;
// this works fine!
}
});
} catch (e) {
print('current user was not found $e');
// this works fine!
}
}
// called inside initState()
setClientOnLoad() async {
await Spryte.checkIfCurrentUserExists();
var doesCurrentUserExist = userIsLoggedIn;
var currentUser = await returnCurrentUser();
if (doesCurrentUserExist == false) {
//if user is not authenticated, set anonymous user
// this works fine!
}
else {
//print('current user does exist');
await foo(currentUser.uid);
// 'foo' is meant to retrieve some data about the client on loading of the app
// so that the user doesn't have to log in every time the app restarts
// but for some reason it's not working for me
}
}
I have got the same problem. I was able to sign in but when restarting the app, I was getting another random UID.
It might sound stupid, but make sure you are not calling signInAnonymously(); at any point in your app without checking if there is already a current user.
This was my problem, I was always signing in anonymously at every app restart.
Here is what I did from my starting app page (which takes care of setting up the app including the user):
Future<FirebaseUser> signInAnonymously() async {
AuthResult result = await _auth.signInAnonymously();
final FirebaseUser user = result.user;
assert(user != null);
assert(await user.getIdToken() != null);
return user;
}
And here is the checking method:
Future<FirebaseUser> tryToFetchUser() async {
var user = await _auth.currentUser();
if (user == null) {
user = await FirebaseAuth.instance.onAuthStateChanged.first;
}
if (user == null) {
user = await signInAnonymously();
}
return Future.value(user);
}
I hope it will help some of you and avoid wasting time on stupid mistakes as I did!
You r calling setClientOnLoad() which is async inside init() method & other app navigation depends on this method so u need wrap all your async stuff in FutureBuilder().
if not then build() method ll be called before complete execution of setClientOnLoad()
e.g. :-
FutureBuilder(
future: setClientOnLoad(),
builder: (context, AsyncSnapshot<R> snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
}
// after executing method completely
},
);