adding authenticated user to firestore 'users' collection flutter - flutter

I am stuck at the adding an authenticated user to a firestore 'users' collection.
Unhandled Exception: [cloud_firestore/not-found] Some requested document
was not found.
User signs in via Google:
class GoogleSignInProvider extends ChangeNotifier {
final GoogleSignIn _googleSignIn = GoogleSignIn();
GoogleSignInAccount _user;
GoogleSignInAccount get user => _user;
AuthService auth = AuthService();
Future googleSignIn(BuildContext context) async {
try {
final googleUser = await _googleSignIn.signIn();
if (googleUser == null) return;
_user = googleUser;
final googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
await FirebaseAuth.instance.signInWithCredential(credential);
} catch (e) {
print(e.toString());
}
final User currentUser = FirebaseAuth.instance.currentUser;
if (currentUser != null)
usersRef.add(currentUser.uid);
Navigator.of(context).pushReplacement(
CupertinoPageRoute(builder: (_) => TabScreen()));
notifyListeners();
}
However, no matter what and how I tried the authentication firebase id is not added to the usersRef (the firestore collection). How do I fix it?
My firestore rules are:
match /users/{userId}/{documents=**} {
allow read: if request.auth.uid != null;
allow write, update, create, delete: if isOwner(userId);
}
function isOwner(userId) {
return request.auth.uid == userId;
}
Help appreciated very much!

so this solved my issue:
final User currentUser = FirebaseAuth.instance.currentUser;
if (currentUser != null)
await usersRef.doc(currentUser.uid).set({'email':
user.email, 'username': user.displayName, 'photoUrl':
user.photoURL});
I think, I was overthinking it..
Thanks, ppl for the directions and help!

Do this.
Map data = {};
FirebaseFirestore.instance
.collection('usersCollection')
.doc(currentUser.uid)
.set(data);
in place of
usersRef.add(currentUser.uid);
Use set when you have doc id and use add when you want an auto generated id.

Related

How to save the user email and name in database while signing in with google?

I am using google auth and i want to save user data in database...How can i get user details here and save it to database?
Future<void> signUpWithGoogle(
BuildContext context,
bool mounted,
) async {
final googleSignIn = GoogleSignIn();
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
try {
await FirebaseAuth.instance.signInWithCredential(credential);
FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.set({
//
});
if (mounted) return;
InfoBox.show(context, InfoBox.success, "Signed In With Google");
} on Exception catch (e) {
if (mounted) return;
InfoBox.show(context, InfoBox.success, e.toString());
}
}
Please modify the code under your try block as below
try {
final authResult = await FirebaseAuth.instance.signInWithCredential(credential);
if (authResult.additionalUserInfo!.isNewUser) {
await FirebaseFirestore.instance
.collection('Users')
.doc(authResult.user!.uid)
.set({
"Name": authResult.user!.displayName,
"Email": authResult.user!.email,
});
}
if (mounted) return;
InfoBox.show(context, InfoBox.success, "Signed In With Google");
} on Exception catch (e) {
if (mounted) return;
InfoBox.show(context, InfoBox.success, e.toString());
}
Please accept the solution if it solves your problem
Inside your try block, you have to get UserCredential which gives the User object data to be saved in the next line.
try{
UserCredential userCredential =
await FirebaseAuth.instance.signInWithCredential(credential);
User user = userCredential.user; // User is updated version of FirebaseUser
FirebaseFirestore.instance.collection('users').doc(user.uid).set(/*Add Mapped User object*/);}
You can use user object to get all the necessary data.

firebase not creating data when user signs for first time

when new user signIn, In firebase Authentication tab it is showing users details.
but not adding the function to firestore.
google signIn code:
Future<UserCredential> signInWithGoogle() async {
showDialog(
context: context,
builder: (context) {
return const Center(child: CircularProgressIndicator());
});
final _auth = FirebaseAuth.instance;
// Trigger the authentication flow
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
// Obtain the auth details from the request
final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication;
// Create a new credential
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
final UserCredential authResult =
await _auth.signInWithCredential(credential);
final user = authResult.user;
if (authResult.additionalUserInfo!.isNewUser) {
if (user != null) {
await DbServices().addNewUser(FirebaseAuth.instance.currentUser!.uid);
}
}
removeLoading();
// Once signed in, return the UserCredential
return await FirebaseAuth.instance.signInWithCredential(credential);
}
removeLoading() {
return Navigator.of(context).pop();
}
}
**this is addNewUser function:**
Future addNewUser(useruid) async {
int heartid = await updateHeartId();
print('updated Heart Id $heartid....................');
await usersCollection.doc(useruid).set({
'user name': FirebaseAuth.instance.currentUser!.displayName,
'uid': useruid,
'heartId': heartid,
'total hearts': 0,
'ringed': false,
'Timestamp': FieldValue.serverTimestamp(),
'profile pic': '',
'todayRinged': false,
'ringedDay': DateTime.now().day,
});
}
when I looked into it, firebase isn't adding the function addNewUser in firestore.
I don't understand what's happening here.
when I signIn for first time the app crashes saying :
> StateError(Bad state: cannot get a field on a DocumentSnapshotPlatform
> which does not exist)
why is the addNewUser function not adding to firestore?

flutter add user data after google sign in

i have a problem with save user data to firestore i using sign in with google auth so after i want to add user data to firestore so i can not do this can you help me thanks.
this is my auth code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
class GoogleSignProvider extends ChangeNotifier{
final googleSignIn = GoogleSignIn();
GoogleSignInAccount? _user;
GoogleSignInAccount? get user => _user;
final FirebaseAuth _auth = FirebaseAuth.instance;
bool result = false;
Future googleLogin()async {
try {
final googleUSer = await googleSignIn.signIn();
if (googleUSer == null ) return;
_user = googleUSer;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final googleAuth = await googleUSer.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
UserCredential userCredential = await _auth.signInWithCredential(credential);
User? user = userCredential.user;
if (user != null){
if (userCredential.additionalUserInfo!.isNewUser) {
await _firestore.collection('users').doc(user.uid).set(
{
'username': user.displayName,
'uid': user.uid,
'profilePhoto': user.photoURL,
}
);
}}
return result;
} catch (e) {
print(e.toString());
}
notifyListeners();
}
Future logout() async {
await googleSignIn.disconnect();
FirebaseAuth.instance.signOut();
}
}
Hey were you able to save the user to firestore? I have pasted the answer that worked for me.
final userGoogle = FirebaseAuth.instance.currentUser!;
await _firestore
.collection('users')
.doc(cred.user!.uid)
.set({
uid: userGoogle.uid,
name: userGoogle.displayName!,
email: userGoogle.email!,
photoURL: userGoogle.photoURL!,
});
I'm curious if this would mean that every time I login using the google account, the photo from the Google account would overwrite the photoURL, assuming it was updated from let's say the profile page. Could help little insight into it.

Flutter - Google Sign In uses previously signed in account (user) even after signing out and signing in with another account

When I hit "Sign in with Google", it does let me choose the account although somehow, the previous user gets loaded.
class GoogleSignInProvider extends ChangeNotifier {
GoogleSignIn? _googleSignIn;
GoogleSignInAccount? _user;
GoogleSignInAccount get user => _user!;
bool _isGoogleLogin = false;
final _auth = FirebaseAuth.instance;
Future signInWithGoogle(context) async {
try {
_googleSignIn = GoogleSignIn();
final googleUser = await _googleSignIn!.signIn();
if (googleUser == null) {
return;
}
_user = googleUser;
final googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
var authCredential = await _auth.signInWithCredential(credential);
_isGoogleLogin = true;
if (authCredential.user != null) {
final snapshot = await FirebaseFirestore.instance
.collection('users')
.doc(authCredential.user!.uid)
.get();
if (!snapshot.exists) {
var userId = authCredential.user!.uid;
FirebaseFirestore.instance.collection('users').doc(userId).set({
"email": googleUser.email,
"workoutsCount": 0,
"lastWorkoutDate": null
});
}
}
notifyListeners();
Navigator.of(context).pushNamed('/dashboard');
} on FirebaseAuthException catch (e) {
showSnackBar(context, e);
} catch (e) {
print('ERROR = ');
print(e);
}
}
Future<void> signOut(context) async {
try {
if (_isGoogleLogin) {
final googleCurrentUser =
GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
if (googleCurrentUser != null) {
await GoogleSignIn().disconnect().catchError((e, stack) {
FirebaseCrashlytics.instance.recordError(e, stack);
});
}
}
await _auth.signOut();
} catch (e) {
showSnackBar(context, e);
} finally {
_isGoogleLogin = false;
Navigator.of(context).pushNamedAndRemoveUntil(
'/register_login', (Route<dynamic> route) => false);
}
}
Is there something wrong with this code??
Can you try to disconnect the account before signing out:
GoogleSignIn _googleSignIn = GoogleSignIn();
await _googleSignIn.disconnect();
await FirebaseAuth.instance.signOut();
You are using firebase auth then please use thsi for signout user :
How to Signout a user in Flutter with Firebase authentication
Remove if (_isGoogleLogin) from your signOut function. googleCurrentUser will check the consitionn and responses based on the result.
First Create a Global variable
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
GoogleSignIn googleSignIn = GoogleSignIn();
Make sure you are using the above variable for login and logout
final googleCurrentUser = firebaseAuth.currentUser;
if (googleCurrentUser != null) {
googleSignIn.signOut();
await firebaseAuth.signOut();
}
User above code for signout user

Everytime i restart the app, it displays the login page, even when there is user data (flutter)

As the title suggests, im only using signInWithGoogle() for my user auth, each time i restart the app it went to Login Page even when the user did not log out.
I know this question has been asked plenty of times, im seeing many answers pointing towards using FirebaseAuth streambuilders but i cant seem to get it to work ... Sorry im a beginner and i do not understand much of the documentations too :(
Is there anyway i can direct the users that are logged in to the main page, and those without user data will have to visit LoginPage first?
sign_in.dart :
import 'package:confApp/main.dart';
import 'package:firebase_auth/firebase_auth.dart' as fauth;
import 'package:google_sign_in/google_sign_in.dart';
import 'package:flutter/material.dart';
String name;
String email;
String imageUrlGoogle;
String id;
final fauth.FirebaseAuth _auth = fauth.FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<bool> signInWithGoogle() async {
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final fauth.AuthCredential credential = fauth.GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final fauth.UserCredential authResult = await _auth.signInWithCredential(credential);
final fauth.User user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
assert(user.email != null);
assert(user.displayName != null);
assert(user.photoURL != null);
assert(user.uid != null);
name = user.displayName;
email = user.email;
imageUrlGoogle = user.photoURL;
id = user.uid;
final fauth.User currentUser = _auth.currentUser;
assert(user.uid == currentUser.uid);
if ( fauth.FirebaseAuth.instance.currentUser != null) {
return true;
} else
return false;
// return 'signInWithGoogle succeeded: $user';
}
void signOutGoogle() async {
await googleSignIn.signOut();
print("User Sign Out");
}
Let me know what other codes that you need, ill update the question with the codes. Thanks in advance!
You need to use SharedPreference Package to save user data. check this package you will know how to handle this. Basically you need to save user data by sharedPref, and retrieve while entering in the app and check if the user data is there you can route to user page, if no user data route to login page.
Here is simple counter number save example:
_incrementCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//Retriving data
int counter = (prefs.getInt('counter') ?? 0) + 1;
print('Pressed $counter times.');
//Saving data
await prefs.setInt('counter', counter);
}
there are prefs.setString/ pref.manymore to save, hope it solves your problem.
LoginPage Code
main.dart
This is how i am setting Data in Shared Preferences during UserLogin
UserID = firebaseuser.uid;
UserName = firebaseuser.displayName;
UserPhoto = firebaseuser.photoURL;
UserEmail = firebaseuser.email;
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('UserID', UserID);
prefs.setString('UserEmail', UserEmail);
prefs.setString('UserName', UserName);
prefs.setString('UserPhoto', UserPhoto);`
And here i am checking whether UserId named shared Preferences data exists or not , if exists then user is logged In if not then User is not logged In to the App
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
SharedPreferences prefs;
Future<void> main() async {
prefs = await SharedPreferences.getInstance();
String UserID = prefs.getString('UserID');
String UserName = prefs.getString('UserName');
String UserEmail = prefs.getString('UserEmail');
String UserPhoto = prefs.getString('UserPhoto');
runApp(
MaterialApp(
home: UserID == null
? App()
:
MyApp(
UserID: UserID,
UserName: UserName,
UserEmail: UserEmail,
UserPhoto: UserPhoto,
)));
}`
Like this You can check whether the user is signed in or not. If signed In u can return
a different screen and if not then a different one