How to get logged in user's email in Flutter using Firebase - firebase

I want to get the email of the logged in user in a Flutter app which uses Firebase for authentication.
I can get the current user by
final user = await _auth.currentUser();
But if I try this to get the mail
final mailID = await _auth.currentUser().email.toString();
I get the following error:
The getter 'email' isn't defined for the type 'Future<FirebaseUser>'.
Try importing the library that defines 'email', correcting the name to the name of an existing getter, or defining a getter or field named 'email'.
How to get the logged in user's email in this case?

Get the user before trying to get the email. code below
<FirebaseUser> user = await _auth.currentUser();
final mailID = user.email;

it's working for me.
import 'package:firebase_auth/firebase_auth.dart';
FirebaseAuth auth = FirebaseAuth.instance;
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});

Related

Update a Firebase anonymous user using Email & Password

People can sign into my app anonymously:
FirebaseAuth.instance.signInAnonymously();
Once inside, they have a little indicator that reminds them if they want be able to save their data across phones, they'll need to sign in. For Google authentication that looks like this:
Future<void> anonymousGoogleLink() async {
try {
final user = await auth.currentUser();
final credential = await googleCredential();
await user.linkWithCredential(credential);
} catch (error) {
throw _errorToHumanReadable(error.toString());
}
}
where googleCredential is:
Future<AuthCredential> googleCredential() async {
final googleUser = await _googleSignIn.signIn();
if (googleUser == null) throw 'User Canceled Permissions';
final googleAuth = await googleUser.authentication;
final signInMethods = await auth.fetchSignInMethodsForEmail(
email: googleUser.email,
);
if (signInMethods.isNotEmpty && !signInMethods.contains('google.com')) {
throw 'An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address.';
}
return GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
}
Now I'd like to do the same thing but instead link the current anonymous account with email and password authentication.
EDIT:
Found a possible solution while writing this. Leaving for others to possibly see. Feel free to correct me.
On the FirebaseUser object the method updatePassword has this doc string:
/// Updates the password of the user.
///
/// Anonymous users who update both their email and password will no
/// longer be anonymous. They will be able to log in with these credentials.
/// ...
You should just be able to update both and then they'll be authenticated as a regular user. For me that looked like:
Future<void> anonymousEmailLink({
#required FirebaseUser user,
#required String email,
#required String password,
}) async {
try {
await Future.wait([
user.updateEmail(email),
user.updatePassword(password),
]);
} catch (error) {
throw _errorToHumanReadable(error.toString());
}
}

How to delete firebase account when user data is deleted on flutter?

is it possible to delete firebase account in authentication on flutter? if yes, how to do that? I have been search but not found the way.
Firestore.instance.collection("users").document(uid).delete().then((_){
// delete account on authentication after user data on database is deleted
});
Using flutter, if you want to delete firebase accounts together with the associated firestore user collection document, the following method works fine. (documents in user collection named by the firebase uid).
Database Class
class DatabaseService {
final String uid;
DatabaseService({this.uid});
final CollectionReference userCollection =
Firestore.instance.collection('users');
Future deleteuser() {
return userCollection.document(uid).delete();
}
}
Use Firebase version 0.15.0 or above otherwise, Firebase reauthenticateWithCredential() method throw an error like { noSuchMethod: was called on null }.
Authentication Class
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future deleteUser(String email, String password) async {
try {
FirebaseUser user = await _auth.currentUser();
AuthCredential credentials =
EmailAuthProvider.getCredential(email: email, password: password);
print(user);
AuthResult result = await user.reauthenticateWithCredential(credentials);
await DatabaseService(uid: result.user.uid).deleteuser(); // called from database class
await result.user.delete();
return true;
} catch (e) {
print(e.toString());
return null;
}
}
}
Then use the following code inside the clickable event of a flutter widget tree to achieve the goal;
onTap: () async {
await AuthService().deleteUser(email, password);
}
Code for deleting user:
FirebaseUser user = await FirebaseAuth.instance.currentUser();
user.delete();
To delete a user account, call delete() on the user object.
For more on this, see the reference documentation for FirebaseUser.delete().
User user = FirebaseAuth.instance.currentUser;
user.delete();
From this you can delete user

Flutter - firebase_auth updateProfile method is not working

I'm creating app using Flutter with Firebase. I have some weird issues. I'm creating authentication and it is working fine but when i try to add some collections to my Firestore Database, the record of displayName is set to null.
Future<FirebaseUser> createUser(email, password, displayName) async {
final FirebaseUser user = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
UserUpdateInfo info = new UserUpdateInfo();
info.displayName = displayName;
_auth.updateProfile(info);
Firestore.instance.collection('users').document().setData({
'name': user.displayName,
'uid': user.uid,
'email': user.email,
'isEmailVerified': user.isEmailVerified,
'photoUrl': user.photoUrl,
});
return user;
}
this is Future class that creates user.
void _handleSubmitted() {
userAuth
.createUser(
emailController.text, passwordController.text, nameController.text)
.then((onValue) {
print("Sign Up button clicked: $onValue");
});
}
this method is handle when sign up button is clicked.
and collection looks like this picture.
If I recall correctly, the local user profile is not immediately updated when you call updateDisplayName or updatePhotoURL. This means you should either just write the local values to the database (easiest) or force a reload of the profile (safest).
Write the local values
As said, this is the simplest approach:
FirebaseFirestore.instance.collection('users').doc().set({
'name': displayName,
'uid': user.uid,
'email': user.email,
'isEmailVerified': user.emailVerified, // will also be false
'photoUrl': user.photoURL, // will always be null
});
Note that emailVerified will always be false, and photoUrl will always be null on a newly created email+password account.
Force a reload of the profile
You can force a reload of the user data by calling FirebaseUser.reload():
await _auth.currentUser!.updateDisplayName(displayName);
await _auth.currentUser!.updateEmail(newEmail);
await _auth.currentUser!.updatePhotoURL(photoURL);
await _auth.currentUser!.reload();
user = _auth.currentUser;
To Update users display name and photo url this will definitely helpful.
FirebaseUser user = await FirebaseAuth.instance.currentUser();
UserUpdateInfo userUpdateInfo = new UserUpdateInfo();
userUpdateInfo.displayName = name;
userUpdateInfo.photoUrl = url;
user.updateProfile(userUpdateInfo);
It's inconvenient the way Firebase Auth works, and they say it won't change for now, so I made a package to address this, grab it here: firebase_user_stream
In the Readme I explain the issues and how the package fixes them, there are examples and etc, enjoy!
EDIT (Jul/2020):
Firebase Auth for Flutter now has a userChanges stream:
which triggers whenever auth state, id token or profile changes occur. Essentially, this acts as a way to obtain realtime changes on currently stateless functionality (such as updateProfile).
I also tried everything but however, this works for me! Just call the FirebaseAuth.instance twice like the one in the code.
FirebaseUser currentUser = await _auth.currentUser();
await currentUser.reload();
currentUser = await _auth.currentUser();
print("Current User ${currentUser.displayName}");
print("Current User ${currentUser.photoUrl}");
hope this helps you!

Example of Firebase Auth with Email and Password on Flutter?

First time implementing Firebase Auth, also new to Flutter dev, and I'm looking to use email and passwords, not Google sign-in. The only examples I see of Firebase Auth being used are anonymously or with Google. Is there a resource / tutorial that shows how to properly set up the calls with the signInWithEmailAndPassword method?
Many thanks!
In my app I have an auth class because I don't like to litter my widget classes with non-widget code, but you can plop this code inside your widget class if you want.
In auth.dart I have:
import 'package:firebase_auth/firebase_auth.dart';
class Auth {
final FirebaseAuth auth = FirebaseAuth.instance;
Future<User> handleSignInEmail(String email, String password) async {
UserCredential result =
await auth.signInWithEmailAndPassword(email: email, password: password);
final User user = result.user!;
return user;
}
Future<User> handleSignUp(email, password) async {
UserCredential result = await auth.createUserWithEmailAndPassword(
email: email, password: password);
final User user = result.user!;
return user;
}
}
Then in my login/register screen I create an instance of my auth class:
var authHandler = new Auth();
Finally, in my login buttons onPressed callback I have:
onPressed: () {
authHandler.handleSignInEmail(emailController.text, passwordController.text)
.then((FirebaseUser user) {
Navigator.push(context, new MaterialPageRoute(builder: (context) => new HomePage()));
}).catchError((e) => print(e));
}
Here is one example from my service. I ask for the email, name and password fields.
registerWithEmail(String name, String email, String password) async {
First I check if the email is already registered with facebook or something.
List<String> providers = await firebaseAuth.fetchProvidersForEmail(email: email);
This is not ideal solution, but you want to handle if the user is already registered, and than link email with current user
if (providers != null && providers.length > 0) {
print("already has providers: ${providers.toString()}");
return handleProviders(providers);
}
Create new User
FirebaseUser newUser = await firebaseAuth.createUserWithEmailAndPassword(email: email, password: password);
await newUser.sendEmailVerification();
This is basically it. I update the name filed of the user, since I have it.
var userUpdateInfo = new UserUpdateInfo();
userUpdateInfo.displayName = name;
await firebaseAuth.updateProfile(userUpdateInfo);
await newUser.reload();
And later You can save the user inside your firestore, where user uid is document ID. So I can get it later.
Git repo with full explanation example for Email/Password Sign in Firebase using flutter
This may help you.
Git Repo: https://github.com/myvsparth/firebase_email_signin
Full Article Step by Step: https://www.c-sharpcorner.com/article/how-to-do-simple-login-with-email-id-in-flutter-using-google-firebase/
This code is for register new user
fb_auth.UserCredential userCredential = await fb_auth
.FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
And this is for login previous user
fb_auth.UserCredential userCredential = await fb_auth
.FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password)
And that fb_auth is
import 'package:firebase_auth/firebase_auth.dart' as fb_auth;

Get Identifier field from Firebase Auth Console

I'm trying to get the email from the user that's currently authenticated using the Facebook Firebase provider. The email is listed under the Identifier field inside the Project's Firebase Authentication Console:
However when I invoke firebase.auth().currentUser the user information loads, however the email field is null. Any ideas on how to get the Identifier (which is where I see the email address) from Firebase? Is this even possible?
Below is the code I'm using:
componentDidMount() {
let user = firebase.auth().currentUser;
let name, email, photoUrl, uid, emailVerified;
if (user !== null) {
name = user.displayName;
email = user.email;
photoUrl = user.photoURL;
emailVerified = user.emailVerified;
uid = user.uid;
console.log(name, email, photoUrl, emailVerified, uid);
}
}
Note: Prevent creation of multiple accounts with the same email address is enabled in Firebase. Also, Facebook API permissions are set to ['public_profile', 'email']
After some testing and debugging I found that the email field will be populated if you're using a regular Firebase Email/Password Sign In method. However, if you're using another Sign In provider method such as Facebook, the email field will appear null (not sure why).
Further inspection of the user object revealed a providerData property.
It's an array that contains all the provider information (including the email address):
So, I updated my code to accommodate this:
componentDidMount() {
let user = firebase.auth().currentUser;
let name, email, photoUrl, uid, emailVerified;
if (user) {
name = user.displayName;
email = user.email;
photoUrl = user.photoURL;
emailVerified = user.emailVerified;
uid = user.uid;
if (!email) {
email = user.providerData[0].email;
}
console.log(name, email, photoUrl, emailVerified, uid);
}
}
In my case, the getEmail() method always returns data for three sign-in possibilities (if user gave authorization to my app to show/use email): Sign in with Email, Sign in with Google, Sign in with Facebook.
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Log.v(TAG,"user.getEmail():"+user.getEmail());
if (user.getEmail() == null){
// User did not authorize the app to show/user email
}
else {
Log.v(TAG,"user.getEmail():"+user.getEmail());
}

Resources