Avoid user Login with Firebase on Creation [duplicate] - firebase

This question already has an answer here:
Flutter - remove auto login after registration in Firebase
(1 answer)
Closed 1 year ago.
I have an app where users are supposed to be created only by Admin User's the problem is that when a new user is created in Firebase the app sign's in with the new user information, so the original logged user (Admin User), has to logged out, and log back in to create a new user.
This is my function to create a new User:
void createUser(
String email,
String password,
String nombre,
String dui,
DateTime fechaNacimiento,
String telefono,
String nombreContacto,
String telefonoContacto,
DateTime fechaIngreso,
String radio,
File foto,
String acceso,
) async {
try {
final auth = FirebaseAuth.instance;
UserCredential authResult = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//var uploadUid = authResult.user?.uid;
final ref = FirebaseStorage.instance
.ref()
.child('user_images')
.child(authResult.user!.uid + '.jpg');
await ref.putFile(foto);
final url = await ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('users')
.doc(authResult.user!.uid)
.set({
'nombre': nombre,
'dui': dui,
'fechaNacimiento': fechaNacimiento,
'telefono': telefono,
'nombreContacto': nombreContacto,
'telefonoContact': telefonoContacto,
'fechaIngreso': fechaIngreso,
'radio': radio,
'foto': url,
'acceso': acceso,
'uid': authResult.user!.uid,
'correo': email,
'contrasena': password,
});
} catch (err) {
print(err);
}
}
Any Ideas on what to do to avoid the log in on user creation of the newly created user.
Kind Regards

The original admin user does not have to be logged out to create a new user. Simply do this.
FirebaseApp secondaryApp = await Firebase.initializeApp(
name: 'SecondaryApp',
options: Firebase.app().options,
);
try {
UserCredential credential = await FirebaseAuth.instanceFor(app: secondaryApp)
.createUserWithEmailAndPassword(
email: 'email',
password: 'password',
);
if (credential.user == null) throw 'An error occured. Please try again.';
await credential.user.sendEmailVerification();
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
return _showError('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
return _showError('An account already exists for this email.');
}
} catch (e) {
return _showError('An error occured. Please try again.');
}
...
// after creating the account, delete the secondary app as below:
await secondaryApp.delete();
The above code will not logout the admin user, the admin user can still continue with normal operations after creating the account.

Related

firebase is not creating the user (user.uid = null)

I am trying to implemente facebook signin in flutter, however, firebase does not create a 'uid'. Doesn't the firebase create a uid automatically?
it returns:
The getter 'uid' was called on null.
Receiver: null
Tried calling: uid
below is the sign in method:
Future<UserCredential> signInWithFacebook(BuildContext context) async {
final LoginResult result = await FacebookAuth.instance.login();
if(result.status == LoginStatus.success) {
final OAuthCredential credential = FacebookAuthProvider.credential(result.accessToken.token);
return await FirebaseAuth.instance.signInWithCredential(credential)
.then((user) async {
final graphResponse = await http.get(Uri.parse(
'https://graph.facebook.com/v2.12/me?
fields=name,picture,email&access_token=${result
.accessToken.token}'));
final Map profile = jsonDecode(graphResponse.body);
if (profile != null){
authService.createUser(name: name, email: email, dob: dob, sex: sex);
}
return user;
});
}
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => Profile()));
return null;
}
The sign in method returns a facebook alert dialog requesting the permission to share email, when press continue red screen with the error appears. why is the firestore not creating the user? Thanks! I am not familiar with the system and just learning.
create user method in authServices:
Future<bool> createUser(
{String name,
User user,
String email,
String password,
String phone,
String sex,
String dob}) async {
var res = await firebaseAuth.createUserWithEmailAndPassword(
email: '$email',
password: '$password',
);
if ((res.user != null)) {
await saveUserToFirestore(name, res.user, email, dob, phone, sex);
return true;
} else {
return false;
}
}
As far as I can understand your code you first login the user with Facebook and then again create a new user with createUserWithEmailAndPassword. If you use the same email for both the second one will fail and give you null.
To track the auth state for all providers use the onAuthStateChanged listener:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
var uid = user.uid;
// ...
} else {
// User is signed out
// ...
}
});
More about it here.

Check if user is logged in or not before authentication using google sign in - flutter

In my flutter app, am trying to check if a user is logged in or not before authenticating the user in firebase, so if he is not then do not authenticate
Future<String> loginUserWithGoogle() async {
String returnValue = "error";
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
UserData _user = UserData();
try {
GoogleSignInAccount _googleUser = await _googleSignIn.signIn();
GoogleSignInAuthentication _googleAuth = await _googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(idToken: _googleAuth.idToken, accessToken: _googleAuth.accessToken);
UserCredential _authResult = await _auth.signInWithCredential(credential);
if (_authResult.additionalUserInfo.isNewUser) {
String userGoogleName = _authResult.user.displayName;
List userSplitName = userGoogleName.split(" ");
String userGoogleFirstName = userSplitName.first;
String userGoogleLastName = userSplitName.last;
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('googleUid', _authResult.user.uid);
await prefs.setString('googleEmail', _authResult.user.email);
await prefs.setString('googleFirstName', userGoogleFirstName);
await prefs.setString('googleLastName', userGoogleLastName);
await prefs.setString('googleUserType', "user");
returnValue = "new";
} else {
_currentUser = await RealDatabase().getUserData(_authResult.user.uid);
if (_currentUser != null) {
returnValue = "success";
}
}
} on PlatformException catch (e) {
returnValue = e.message;
} catch (e) {
print(e);
}
return returnValue;
}
}
Here what I want to check is that if it is a new user then save his google data in sharedpreference and take him to another page where he can complete some other registration and then sign him in. but what this code does is that if it is a new user it will authenticate, save the info in sharedpeference and then take him to the page and if maybe that user decided to go back to the previous page (since i use Navigator.push(context)) and still click the google sign in button again then it will take him to the home screen without him completing the other registration I want him to do because it already authenticated him first. So please is there a way to do this without first authenticating the user.
You can use stream provider to control if user logged in or not.
Here is an example how to use stream provider in your project;
https://flutterbyexample.com/lesson/stream-provider.

Firebase + Flutter: can't lock access to unverified email accounts

I'd like to block out people who didn't verify their email so i figured out this code for sign up:
// sign up
Future signUp(String email, String password) async {
try {
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
} catch (e) {
print('An error has occured by creating a new user');
print(
e.toString(),
);
}
try {
final FirebaseUser _user = await _auth.currentUser();
await _user.sendEmailVerification();
} catch (error) {
print("An error occured while trying to send email verification");
print(error.toString());
}
try {
await _auth.signOut();
} catch (err) {
print(err);
}
}
and this for sign in:
//Sign In with Email and Pass
Future signInWithEmailAndPassword(String email, String password) async {
FirebaseUser _user = await FirebaseAuth.instance.currentUser();
if (_user != null && _user.isEmailVerified == true) {
try {
await _auth.signInWithEmailAndPassword(
email: email, password: password);
return _user;
} catch (e) {
return null;
}
} else {
return null;
}
}
_auth is just an instance of FirebaseAuth.
The problem is that i can login even if i didnt verify the email.
Firebase Auth doesn't stop accounts from signing in if the user hasn't verified their email address yet. You can check that property _user.isEmailVerified to find out the state of that validation after the user signs in, and you can determine from there what the user should see.
isEmailVerified can be a little bit of trouble to get working correctly.
Make sure you are calling
await FirebaseAuth.instance.currentUser()..reload();
before your are calling isEmailVerified also in my own experience and I don't know if this is just something I was doing wrong but this did not work from my Auth class this did not start working until I put the code directly in initState() of my widget that checks whether the user is verified. Like I said that part might have been something I did wrong. Like stated this will not listen for change you must check yourself either periodically or at a point that you know email is verified.
Future(() async {
_timer = Timer.periodic(Duration(seconds: 10), (timer) async {
await FirebaseAuth.instance.currentUser()
..reload();
var user = await FirebaseAuth.instance.currentUser();
if (user.isEmailVerified) {
timer.cancel();
Navigator.of(context).popAndPushNamed(HearingsScreen.routeName);
}
});
});
So it checks every 10 seconds to see if the user has verified their email not the most elegant solution. The page I have this on just displays a message 'Please verify your email' so its not like this is interrupting other code. If your app is performing other tasks this might not be an option for you. If you want to play around with isEmailVerified go ahead but i spent a week of headaches until i settled on this.

Write to Firebase Firestore denied - Flutter

I am trying to save the users who sign in in the firebase database.
this is the function which is used to update the signed in user in the firebase, the fuction uses a uid to create a document with this id :
final Firestore _db = Firestore.instance;
void upadteUserData(FirebaseUser user) async {
DocumentReference ref = _db.collection("users").document(user.uid);
print("in update");
return ref.setData({
"uid": user.uid,
'email': user.email,
'displayName': user.displayName,
//'emergency': []
}, merge: true);
}
and here is the sign in fuction:
Future signInWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
upadteUserData(user);
print("signing in");
print(result.user.email);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
here's the console after signing in
I tried it twice and it was working perfectly fine 3 weeks ago. However, when I try to sign in today with different e-mails, it did not update the fire base. Any idea?

How to use timer in flutter app for changing data?

I am using shared preferences to store the token, email, username and other user details when a user logs in using firebase authentication. The firebase token expires in every one hour so I need to refresh the token on the basis of when the user has returned to the app which I am doing in getCurrentUser() function below. I want to know that if a user has logged in my app, used it for 5 minutes or so and then close the application, will that timer function would still be listening and call the function after the timeout or not?
If it doesn't do so then How can I achieve checking this?
void checkTokenValidity(int time) {
Timer(Duration(seconds: time), () async {
print('token timed out');
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('token', 'expired');
prefs.remove("currentUser");
});
}
Future<String> getCurrentUser() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String currentToken = prefs.getString('token');
final String cuser = prefs.getString('currentUser');
print("current: $cuser");
if (cuser != null && currentToken != 'expired') {
print('signed in and $currentToken');
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token');
String uid = prefs.getString('userId');
String email = prefs.getString('userEmail');
String photo = prefs.getString('photo');
_authenticatedUser =
User(email: email, id: uid, token: token, photo: photo);
return 'success';
} else if (currentToken == 'expired') {
print('token is expired');
final FirebaseUser user = await FirebaseAuth.instance.signInAnonymously();
var token = await user.getIdToken();
prefs.setString('token', token);
String uid = prefs.getString('userId');
String email = prefs.getString('userEmail');
String photo = prefs.getString('photo');
_authenticatedUser =
User(id: uid, email: email, token: token, photo: photo);
checkTokenValidity(3600);
return 'token';
} else {
print('user is null');
return null;
}
}
In my authentication function which is not here, I have called checkTokenValidity(3600) just after the user successfully logs in.
I have also tried using FirebaseUser user = await FirebaseAuth.instance.currentUser(); but that also didn't solve the problem.
You went the wrong way. The right way is to add error handler on 401 (Unauthorized) error and handle it by refreshing token and retrying the same query.

Resources