How to check whether the user email id exists? - firebase

I am using the below code for google sign in flutter app with firebase, which is working successfully.
How should I check that whether the email id used is already existing in the firebase authentication?
This I need to ensure that I update the user information in the firestore database accordingly.
Future<User> _handleSignIn() async {
User user;
bool userSignedIn = await _googleSignIn.isSignedIn();
setState(() {
isUserSignedIn = userSignedIn;
});
if (isUserSignedIn) {
user = _auth.currentUser;
}
else {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
user = (await _auth.signInWithCredential(credential)).user;
userSignedIn = await _googleSignIn.isSignedIn();
setState(() {
isUserSignedIn = userSignedIn;
});
}
return user;
}
Please guide me for this

There is a Generic exception related to Firebase Authentication. which is the class FirebaseAuthException. It comes with codes related to errors including email already exists so you would write something like:
try {
//your signIn method here
//i assumed handleSignIn
handleSignIn();
} on FirebaseAuthException catch (e) {
//exception that occurs if e-mail already exists
if (e.code == 'email-already-in-use') {
// the rest of your code here
}
}

Then this is the method you should use I have used to solve my problem
this is my auth.dart file
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:gfd_official/User/User.dart';
import 'package:gfd_official/services/database.dart';
import 'package:google_sign_in/google_sign_in.dart';
String photoUrl;
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on firebase user
Userdat _userFromFirebaseUser(User user) {
return user != null ? Userdat(uid: user.uid) : null;
}
// auth change user stream
Stream<Userdat> get user {
return _auth
.authStateChanges()
//.map((FirebaseUser user) => _userFromFirebaseUser(user));
.map(_userFromFirebaseUser);
}
Future signInWithGoogle() async {
GoogleSignIn googleSignIn = GoogleSignIn();
final acc = await googleSignIn.signIn();
final auth = await acc.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: auth.accessToken, idToken: auth.idToken);
try {
final res = await _auth.signInWithCredential(credential);
User user = res.user;
photoUrl = user.photoURL;
UserHelper.saveUser(user);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
Future logOut() {
try {
GoogleSignIn().signOut();
return _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
class UserHelper {
static FirebaseFirestore _db = FirebaseFirestore.instance;
static saveUser(User user) async {
Map<String, dynamic> userData = {
"name": user.displayName,
"email": user.email,
"role": "basic",
};
try {
final userRef = _db.collection("users").doc(user.uid);
if ((await userRef.get()).exists) {
await userRef.update({});
} else {
await _db
.collection("users")
.doc(user.uid)
.set(userData, SetOptions(merge: true));
}
} catch (e) {
print(e.toString());
}
}
}
In this the save user function will create database for new user and if user already exist then it will let it remain same as it is.
I am creating a document for every user with his/her uid.

Related

How to access the uid of a google-registered user for our Firestore collection?

I am creating a flutter app. The point is that in my database, I want the users to be recognized with their uid. For users registered with email & password, there is no problem because I can easily access to their uid with user.uid. But when the user registers with his google account, I don't know how to access to his uid. I just know how to access to his id which is different by running _user.id. How to access the user's uid in this case? Here's the code:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
final googleSignIn = GoogleSignIn();
GoogleSignInAccount? _user;
// create user object based on firebase user
Users? _userFromFirebaseUser(User? user) {
return user != null ? Users(uid: user.uid) : null;
}
// auth change user stream
Stream<Users?> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
//register with email & psswrd
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
User? user = result.user;
await DatabaseService(uid: user!.uid).updateUserData('new user', 0);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
Future signInithGoogle() async {
try {
final result = await googleSignIn.signIn();
if (result == null)
return await DatabaseService(uid: _user!.id)
.updateUserData('new user', 0);
_user = result;
final googleAuth = await result.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
await _auth.signInWithCredential(credential);
} catch (e) {}
}
The 'updateUserData' function creates a new record for the user when he registers. The DatabaseService class contains all the functions related to Firestore. here it is:
class DatabaseService {
final String uid;
DatabaseService({required this.uid});
// collection reference
final CollectionReference userCollection =
FirebaseFirestore.instance.collection('users');
Future updateUserData(String name, int points) async {
return await userCollection.doc(uid).set({
'name': name,
'points': points,
});
}
}
When you call await _auth.signInWithCredential(credential), you get back a UserCredential, which is the same that you get back from await FirebaseAuth.instance.signInWithEmailAndPassword(...).
So you can get the UID from the UserCredential in both cases with:
var credentials = await _auth.signInWithCredential(credential);
var uid = credentials.user!.uid
If you're listening to auth state changes, then that will fire when you sign in with any provider, and you'll get a User? object. So you can get the UID from that with:
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User ${user.uid} is signed in!');
}
});

Google authentication problem (Flutter and Firebase)

I am flutter-newbie and I have one problem: I want to add Google authentication to my flutter app with firebase. This is my code for login screen:
import 'package:PixiCall/resources/firebase_repository.dart';
import 'package:PixiCall/screens/home_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
FirebaseRepository _repository = FirebaseRepository();
#override
Widget build(BuildContext context) {
return Scaffold(
body: loginButton(),
);
}
Widget loginButton() {
return FlatButton(
padding: EdgeInsets.all(35),
child: Text(
'Login',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w900,
letterSpacing: 1.2,
),
),
onPressed: () => performLogin,
);
}
void performLogin() {
_repository.signIn().then((User user) {
if (user != null) {
authenticateUser(user);
} else {
print('There was an error');
}
});
}
void authenticateUser(User user, BuildContext context) {
_repository.authenticateUser(user).then((isNewUser) {
if (isNewUser) {
_repository.addDataToDb(user).then((value) {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return HomeScreen();
}));
});
} else {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return HomeScreen();
}));
}
});
}
}
I have this error here:
lib/screens/login_screen.dart:39:25: Error: Too few positional arguments: 2 required, 1 given.
authenticateUser(user);
What is the other parameter which I have to add?
Also I think that I have one more mistake in other file. This is the code from other file:
import 'package:PixiCall/models/user.dart';
import 'package:PixiCall/utils/utilities.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class FirebaseMethods {
final FirebaseAuth _auth = FirebaseAuth.instance;
GoogleSignIn _googleSignIn = GoogleSignIn();
static final FirebaseFirestore firestore = FirebaseFirestore.instance;
//user class
User1 user = User1();
Future<User> getCurrentUser() async {
User currentUser;
currentUser = await _auth.currentUser;
return currentUser;
}
Future<User> signIn() async {
GoogleSignInAccount _signInAccount = await _googleSignIn.signIn();
GoogleSignInAuthentication _signInAuthentication =
await _signInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: _signInAuthentication.accessToken,
idToken: _signInAuthentication.idToken,
);
User user = await _auth.signInWithCredential(credential);
return user;
}
Future<bool> authenicateUser(User user) async {
QuerySnapshot result = await firestore
.collection('users')
.where('email', isEqualTo: user.email)
.get();
final List<DocumentSnapshot> docs = result.docs;
//if user is registered then length of list > 0 or else less than 0
return docs.length == 0 ? true : false;
}
Future<void> addDataToDb(User currentUser) async {
String username = Utils.getUsername(currentUser.email);
user = User1(
uid: currentUser.uid,
email: currentUser.email,
name: currentUser.displayName,
profilePhoto: currentUser.photoURL,
username: username);
firestore.collection('users').doc(currentUser.uid).set(user.toMap(user));
}
}
This is the mistake in console:
lib/resources/firebase_methods.dart:32:17: Error: A value of type 'UserCredential' can't be assigned to a variable of type 'User'.
Sorry if I confused you, as I said, I am newbie. If you want any other informations please ask here.
For the first mistake , you defined a function void authenticateUser(User user, BuildContext context) so when you use it, it expects 2 arguments a User type object and a BuildContext object
Then you are calling this function in
void performLogin() {
_repository.signIn().then((User user) {
if (user != null) {
authenticateUser(user);
} else {
print('There was an error');
}
});
}
You are passing only the User object, missing the BuildContext
For GoogleSingIn this was my solution:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
//create user object based on FB json
User _userFromFirebaseUser(FirebaseUser user) {
return user != null
? User(uid: user.uid, emailVerified: user.isEmailVerified)
: null;
}
//auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
Future<User> singInUsingGoogle() async {
int age;
String email;
String name;
String lastname;
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
final result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
print(result.user.providerData);
await DatabaseService(uid: user.uid).createUserData(
//user info
)

Firebase can not change displayName ,displayName is null on every way

Can't add I more user information with await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: _email, password: _password); function?
part of signup.dart file:
String _email, _password, _name;
final formkey = new GlobalKey<FormState>();`
Future<void> registered() async {
if (formkey.currentState.validate()) {
formkey.currentState.save();
try {
await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: _email, password: _password);
FirebaseUser firebaseUser = await FirebaseAuth.instance.currentUser();
Firestore.instance
.collection("users")
.document(firebaseUser.uid)
.setData({"name": _name});
await firebaseUser.reload();
firebaseUser = await FirebaseAuth.instance.currentUser();
print(
"${firebaseUser.uid},${firebaseUser.email},${firebaseUser.displayName} , $_password this user has been created-----");
} catch (e) {
print("${e.message} message--------------------------------------");
}
} else {
print("somthing went wrong");
}
}
I have tried many way to do this but still i have no result
You are saving data in Firestore, and trying to get the name from Firebase Auth. Those are two services. Instead of trying to use firestore, what you could is,
FirebaseUser firebaseUser = await FirebaseAuth.instance.currentUser();
var userUpdateInfo = UserUpdateInfo();
userUpdateInfo.displayName = _name;
firebaseUser.updateProfile(userUpdateInfo);
await firebaseUser.reload();
firebaseUser = await FirebaseAuth.instance.currentUser();
After creating the account using the method .createUserWithEmailAndPassword pass the value of the user to another class by
final FirebaseAuth _auth = FirebaseAuth.instance;
//user object based on firebase
User _userFromFirebase(FirebaseUser user){
return user != null ? User(uid: user.uid):null;
}
Future loginWithEmailAndPass(String email,String password)async{
try{
AuthResult result = await _auth.signInWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
return _userFromFirebase(user);
}catch(e){
print(e.toString());
return null;
}
}
Pass the value of user to a new class by creating a new dart file
class User{
final String uid;
User({this.uid});
}
Include that dart file in the home page for the user name.
Refer this tutorial for guidance.
https://youtu.be/Jy82t4IKJSQ?list=PL4cUxeGkcC9j--TKIdkb3ISfRbJeJYQwC

Firebase.instance.signOut() not setting the currentUser() to null

Why is my signOut() method not setting the currentUser() to null??
When I click on logout on my homepage it checks the isAuthenticated() method which is returning a user instead of null. Also, just have a look at the two comments I've included inside the logout() method.
Thank You!!
Here's my code -
class Auth with ChangeNotifier {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
bool isAuthenticated() {
print('$currentUser inside the isAuthenticated');
if (currentUser == null) {
print('false');
return false;
}
print('true');
return true;
}
Future<FirebaseUser> get currentUser async {
return await _auth.currentUser();
}
Future<FirebaseUser> signInWithEmail(String email, String password) async {
try {
final response = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
print(response);
if (response == null) {
print('response is null');
} else {
notifyListeners();
return response.user;
}
} catch (error) {
print('some error');
throw error;
}
}
Future<FirebaseUser> signInWithGoogle() async {
try {
final GoogleSignInAccount _userDetails = await _googleSignIn.signIn();
if (_userDetails == null) {
print('No user found');
} else {
final GoogleSignInAuthentication googleAuth =
await _userDetails.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final FirebaseUser user =
(await _auth.signInWithCredential(credential)).user;
return user;
}
notifyListeners();
print('google sign in ran successfully');
} catch (error) {
throw error;
}
}
Future<FirebaseUser> logout() async {
try {
print('logout ran');
print(currentUser); //THIS RETURNS AN INSTANCE OF USER
_auth.signOut().then( (response) {
print('signout successful');
});
await _googleSignIn.signOut();
print(currentUser); //THIS *ALSO* RETURNS AN INSTANCE OF USER
notifyListeners();
return currentUser;
} catch (error) {
print('an error');
}
}
}
I know there would a silly mistake that I'm unable to catch but it's tiring now!! I've tried other methods that I could find on stackoverflow
May be the future is not complete when you try getting current user, have you tried await instead of then in logout?
Future<FirebaseUser> logout() async {
try {
print('logout ran');
print(currentUser); //THIS RETURNS AN INSTANCE OF USER
await _auth.signOut();
await _googleSignIn.signOut();
//The problem is with this, you need to await this
//print(currentUser); //THIS *ALSO* RETURNS AN INSTANCE OF USER
var user = await currentUser;
print(user); //prints null
notifyListeners();
return currentUser;
} catch (error) {
print('an error');
}
}
I faced similar issue and worked it around by assigning null to currentUser. It works fine now!
case R.id.main_logout_option:
updateUserStatus(getString(R.string.strOffline));
mAuth.signOut();
currentUser = null;
goToLoginActivity();
break;

Check if user exists on FIrestore

I have this function that use SignInWithGogle to Sign In/Up an user
void _signInWithGoogle() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final FirebaseUser user = (await _auth.signInWithCredential(credential)).user;
assert(user.email != null);
assert(user.displayName != null);
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
print('user email here $user.email');
setState(() {
if (user != null) {
_success = true;
_userID = user.uid;
final userToSubmit = User(
email: user.email,
id: user.uid,
name: user.displayName,
owner: false,
favorites: null);
print('USER ID USER ID USER ID ${user.uid}');
DocumentReference dbRef =
Firestore.instance.collection('users').document(user.uid);
dbRef.get().then((value) {
print('VALUE EXISTS? ${value.exists} y VALUE $value');
value.exists ?
_goToHomeScreen(user)
:
dbRef
.collection('prf')
.document('profile')
.setData(userToSubmit.toJson())
.then(_goToHomeScreen(user));
});
} else {
_success = false;
}
});
}
The problem is that when the user logOut and then login it sets the new Data and the user lost everything they have like favorites and so on... I thought that checking if the document exists should resolve the problem, but despite the document is there exists returns false.
This is the piece of code I'm talking about
DocumentReference dbRef =
Firestore.instance.collection('users').document(user.uid);
dbRef.get().then((value) {
print('VALUE EXISTS? ${value.exists} y VALUE $value');
value.exists ?
_goToHomeScreen(user)
:
dbRef
.collection('prf')
.document('profile')
.setData(userToSubmit.toJson())
.then(_goToHomeScreen(user));
});
}
Why it returns false even if the user.uid and the document exists? What am I doing wrong?
The final solution I implemented is this:
FirebaseUser firebaseUser;
try {
firebaseUser = (await FirebaseAuth.instance.signInWithCredential(credential)).user;
} catch(e) {
print(e.toString());
} finally {
final userToSubmit = User(
email: firebaseUser.email,
id: firebaseUser.uid,
name: firebaseUser.displayName,
owner: false,
restauranteAdded: false);
DocumentReference dbRef =
Firestore.instance.collection('users').document(firebaseUser.uid).collection('nameOfTheCollection').document('documentName');
dbRef.get().then((data) {
data.exists ? _goToHomeScreen(user) :
_createUser();
});
This way I check if user document exists in my Firestore Database and if not it creates it.
There is a lot going on. In general, you're not updating any state object with the setState() method. setState is used to tell a widget that some state has changed--and it's called synchronously with the change, but here where you're just checking to see if a document exists and nothing is changing, it's not needed.
Also it doesn't appear that you're actually returning a user object at all, so this code as I read it will always return false.
You should remove setState here altogether (not needed for what you're doing)
Run a sign in method that returns the user object you want do do things with.
Access your db once you know you have a signed in user (i.e. w/ uid of signed in user)
Here is an option to try:
//Create a User class so that you don't have to call FireBase in your methods.
class User {
User({
#required this.uid,
this.email,
this.displayName,
});
final String uid;
final String email;//these are whatever you want
final String displayName;
}
//put sign in methods into an abstract class. Don't have to, but keeps code flexible if you don't stay with firebase
abstract class AuthBase {
//add in other signin methods as needed
Future<User> signInWithGoogle();
}
//Implement AuthBase in class Auth
class Auth implements AuthBase {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
//Get a User from Firebase User
User _userFromFirebase(FirebaseUser user) {
if (user == null) {
return null;
}
return User(
uid: user.uid,
displayName: user.displayName,
email: user.email,
);
}
//your signinWithGoogle method
Future<User> signInWithGoogle() async {
//where User is the class you've created
GoogleSignIn googleSignIn = GoogleSignIn();
GoogleSignInAccount googleUser = await googleSignIn.signIn();
if (googleUser != null) {
GoogleSignInAuthentication googleAuth = await googleUser.authentication;
if (googleAuth.idToken != null && googleAuth.accessToken != null) {
final authResult = await _firebaseAuth.signInWithCredential( //await your instance of FirebaseAuth
GoogleAuthProvider.getCredential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken,
),
);
return _userFromFirebase(authResult.user); //your signed in firebase user that you can do stuff with uid, email, displayname, etc.
} else {
throw PlatformException(
code: 'ERROR_MISSING_GOOGLE_AUTH_TOKEN',
message: '',
);
}
} else {
throw PlatformException(
code: 'ERROR_ABORTED_BY_USER',
message: '',
);
}
}

Resources