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

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.

Related

The getter 'uid' not defined

i'm trying to create a food track app on android studio, it's my first time and i'm working with firebase_auth 3.3.12. my code in the aut.dart is:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:my_firstapp/models/user_model.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
AuthService();
// create user object based on FirebaseUser.
UserModel _userFromUser(User) {
return user != null ? UserModel(uid: user.uid) : null;
}
// auth change user stream
Stream<UserModel> get user {
return _auth.authStateChanges()
.map(_userFromUser);
}
Future<UserModel> getUser() async {
User user = await _auth.currentUser();
return _userFromUser(user);
}
// sign in with email and password
Future signInWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
User user = result.user;
return _userFromUser(user);
} catch(e) {
print(e.toString());
return null;
}
}
// sign up with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user;
// create a new user document in database
return _userFromUser(user);
} catch(e) {
print(e.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch(e){
print(e.toString());
return null;
}
}
}
However i'm getting 2 errors:
-The getter 'uid' isn't defined for the type 'Stream';
-The expression "await _auth.currentUser()" doesn't evaluate to a function, so it can't be invoked.
How can i rewrite the code? thanks
The _auth.currentUser is not a function (it used to be, but changed about a year ago), but rather a property. It also isn't asynchronous, so you don't need await nor to return a Future.
So:
UserModel getUser() {
User user = _auth.currentUser;
return _userFromUser(user);
}
In this code, your argument is capitalised ('User') but in the code block you write 'user'.
UserModel _userFromUser(User) {
return user != null ? UserModel(uid: user.uid) : null;
}
Furthermore, for _auth.currentUser(), you do not need to use await as it does not return a future.

Firebase Authentication with Flutter not working

I am trying to create a signup page which should give an error message if user with particular email id already exist. But it's not working.
signUp() {
if (formkey.currentState!.validate()) {
Map<String, String> userDataMap = {
"name": usernameC.text,
"email": emailC.text
};
setState(() {
isLoading = true;
});
authMethods.signUp(emailC.text, passwordC.text).then((value) {
databaseMethods.uploadUserData(userDataMap);
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => ChatRoom()));
});
}
}
It calls the signUp() function from auth.dart given below
UserData? _userFromFirebase(User? user) {
return user != null ? UserData(userid: user.uid) : null;
}
Future signUp(String email, String pass) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: pass);
User? user = result.user;
return _userFromFirebase(user);
} catch (e) {
print(e}
}
Every time I signup with same email it doesn't give any error.
If you sign up with the same email you should get this message:
[firebase_auth/email-already-in-use] The email address is already in use by another account.
I use print(e.hashCode) and then use this hash code to show an error message.
Ok I tried this method and it worked out. Just added null check for the "value" attribute in.
authMethods.signUp(emailC.text, passwordC.text).then((value)
It was returning null without any other message. That's why I was unable to see the error.

The above code will give me null in the field since my app uses password authentication

void _addMessage(String value) async {
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
await FirebaseFirestore.instance.collection("interest_chat").add({
'author': user.displayName ?? "Anonymous",
'author_id': user.uid,
'timestamp': Timestamp.now().millisecondsSinceEpoch,
'value': value,
});
}
}
The above code will give me null in the 'author' field since my app uses password authentication. But i want to display the username which is stored in another collection of firebase, it is in the location of FirebaseFirestore.instance.collection("users").doc(user!.uid)
I'm really new to flutter and firebase, this is my first app i am making for my school project, any help or guidance will be appriciated.
Your question could've been framed better but based on my understanding, it seems new users do not have a displayName associated with the user object since you are using the email_id + password sign up option and you wish to retrieve the username which is stored in another collection of firestore under "users".
Future<String> _getUsername() async {
final user = FirebaseAuth.instance.currentUser;
final docSnap =
await FirebaseFirestore.instance.collection("users").doc(user!.uid).get();
return docSnap.get(
'userName'); //assuming the field within the document is titled ‘userName’
}
void _addMessage(String value) async {
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
final userName = await _getUsername();
await FirebaseFirestore.instance.collection("interest_chat").add({
'author': userName,
'author_id': user.uid,
'timestamp': Timestamp.now().millisecondsSinceEpoch,
'value': value,
});
}
}

Avoid user Login with Firebase on Creation [duplicate]

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.

Flutter - Get Firebase custom claims while writing Firebase user to own user instance

I am trying to implement the example given at How do I access custom claims? to my existing code.
I have a Stream which listens to auth changes and updates my own user object with the responded Firebase user. When I store my user object, I would like to get the custom claims of that user as well.
The problem is in _userFromFirebaseUser.
It says "The await expression can only be used in an async function.
Try marking the function body with either 'async' or 'async*'."
But when I do so, the error is hops to my stream where it then says "The argument type 'Future Function(User)' can't be assigned to the parameter type 'User Function(User)'." for "_userFromFirebaseUser" in
// auth change user stream
Stream<local.User> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
Here is my complete authentication class:
import 'package:<my-pckg>/models/user.dart' as local;
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:<my-pckg>/services/database.dart';
//import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
final auth.FirebaseAuth _auth = auth.FirebaseAuth.instance;
// create user obj based on firebase user
local.User _userFromFirebaseUser(auth.User user) {
final isAdmin = (await _currentUserClaims)['admin'] == true;
return user != null
? local.User(
uid: user.uid,
email: user.email,
displayName: user.displayName,
isAdmin: isAdmin)
: null;
}
// auth change user stream
Stream<local.User> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
// sign in anon
Future signInAnon() async {
try {
auth.UserCredential result = await _auth.signInAnonymously();
auth.User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in with email and password
Future signInWithEmailAndPassword(String email, String password) async {
try {
auth.UserCredential result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
auth.User user = result.user;
print('Successfully logged in, User UID: ${user.uid}');
return user;
} catch (error) {
print(error.toString());
return null;
}
}
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
auth.UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
auth.User user = result.user;
// create a new document for the user with the uid
await DatabaseService(uid: user.uid).updateUserData(null);
print('Successfully registered, User UID: ${user.uid}');
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
print('User signed out');
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
}
Future<Map<dynamic, dynamic>> get _currentUserClaims async {
final user = _auth.currentUser;
// If refresh is set to true, a refresh of the id token is forced.
final idTokenResult = await user.getIdTokenResult(true);
return idTokenResult.claims;
}
}
Am I heading into the wrong direction? Is there anything obvious, that I simply do not consider?
Thanks for your help!
For those, heading into the same problem, I found the solution after further research:
You will have to change the .map to .asyncMap.
Here is the code, which works for me:
import 'package:<my-pckg>/models/user.dart' as local;
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:<my-pckg>/services/database.dart';
//import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
final auth.FirebaseAuth _auth = auth.FirebaseAuth.instance;
// create user obj based on firebase user
Future<local.User> _userFromFirebaseUser(auth.User user) async {
final isAdmin = (await _userClaims)['admin'] == true;
return user != null
? local.User(
uid: user.uid,
email: user.email,
displayName: user.displayName,
isAdmin: isAdmin)
: null;
}
// auth change user stream
Stream<local.User> get user {
return _auth.authStateChanges().asyncMap(_userFromFirebaseUser);
}
// sign in anon
Future signInAnon() async {
try {
auth.UserCredential result = await _auth.signInAnonymously();
auth.User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in with email and password
Future signInWithEmailAndPassword(String email, String password) async {
try {
auth.UserCredential result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
auth.User user = result.user;
print('Successfully logged in, User UID: ${user.uid}');
return user;
} catch (error) {
print(error.toString());
return null;
}
}
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
auth.UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
auth.User user = result.user;
// create a new document for the user with the uid
await DatabaseService(uid: user.uid).updateUserData(null);
print('Successfully registered, User UID: ${user.uid}');
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
print('User signed out');
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
}
Future<Map<dynamic, dynamic>> get _userClaims async {
final user = _auth.currentUser;
// If refresh is set to true, a refresh of the id token is forced.
final idTokenResult = await user.getIdTokenResult(true);
return idTokenResult.claims;
}
}
Found here: In flutter, how can I "merge" Firebase onAuthStateChanged with user.getTokenId() to return a Stream?

Resources