Link Multiple Auth Providers to an Account - firebase

I have implemented Facebook and Google sign in.
But FireBase document says this will cause an error if the same user first signs up with Facebook and later try sign in with Google (with the same email).
So I follow doc and try to configure account linking.
But I do not know how to do.
Should I try link account every time user is logged in? Problem is I not know if the user already has signed in with another auth provider.
For example, the original code has:
Google:
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);
}
Facebook:
void _signInWithFacebook() async {
final AuthCredential credential = FacebookAuthProvider.getCredential(
accessToken: _tokenController.text,
);
final FirebaseUser user = await _auth.signInWithCredential(credential);
}
Is correct to call every time in _signInWithFacebook() and _signInWithGoogle() :
user = await auth.linkWithCredential(credential);
For example:
void _signInWithFacebook() async {
final AuthCredential credential = FacebookAuthProvider.getCredential(
accessToken: _tokenController.text,
);
final FirebaseUser user = await _auth.signInWithCredential(credential);
user = await auth.linkWithCredential(credential); //new
}
How I can implement correctly?
Thanks!

When the user enters their email address to sign in, you'll want to use fetchSignInMethodsForEmail() to find out if that email address is already known.
If a user has already signed up with another provider, that's a good moment to ask them if they want to merge those accounts, and then call the account linking API.

Related

How to access Google username for flutter authentication. Lit Firebase Auth

I'm a bit new to this, but I'm confused about how to access a user's Google username when signing in with Google. I used Lit Firebase Auth so that basically I have to just say
context.signInWithGoogle();
But I need a display name as in my database when a user signed up with email they could enter a username, by which the text they entered would be stored and then later display as their username.
Here is my register.dart
try {
await Firebase.initializeApp();
UserCredential user = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
User updateUser = FirebaseAuth.instance.currentUser;
updateUser.updateProfile(
displayName: _usernameController.text);
userSetup(_usernameController.text);
Navigator.of(context).pushAndRemoveUntil(
HomeScreen.route, (route) => false);
}
And the important part is the
userSetup
Which from my database will take that text and update the displayName.
So I guess I'm asking what to fill userSetup() instead of _usernameController.text in the case of Google sign in.
You can try out the following code for the google signing in flutter and getting credential from google and use them to firebase and the variable user contain all the user information like email, imageurl and name.
GoogleSignIn _googleSignIn = new GoogleSignIn();
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn();
GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
AuthCredential credential = GoogleAuthProvider.credential(idToken: googleSignInAuthentication.idToken, accessToken: googleSignInAuthentication.accessToken);
var result = (await _auth.signInWithCredential(credential));
_user = result.user;

Flutter Firebase - failing to properly delete a Google authenticated user

I'm trying but failing to re-trigger the authentication steps that the user gets taken through when they authenticate themselves using Google sign-in, following deletion of the user. The deleted user simply gets signed in immediately (instead of being taken through the authentication steps), when using Google sign-in the second time. I want to be able to re-trigger the authentication steps for my own testing purposes.
Specifically, I've got a user who I've authenticated and signed in as per the FlutterFire documentation, i.e.
Future<UserCredential> signInWithGoogle() async {
// 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 GoogleAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// Once signed in, return the UserCredential
return await FirebaseAuth.instance.signInWithCredential(credential);
}
I then proceed to delete the user; again, as per the FlutterFire documentation, i.e.
try {
await FirebaseAuth.instance.currentUser.delete();
} catch on FirebaseAuthException (e) {
if (e.code == 'requires-recent-login') {
print('The user must reauthenticate before this operation can be executed.');
}
}
That works, insomuch as the user is no longer listed amongst the authenticated users in the Firebase console. However, if I now proceed to call signInWithGoogle() again, then instead of getting taken through the authentication steps again (i.e. being prompted to enter an email, password, etc.), the user simply gets signed in straight away. It's as if the user hasn't been properly deleted. How would I go about re-triggering the authentication steps?
You must also call GoogleSignIn().signOut() after the Firebase sign out or delete.
In my case, I had to reauthenticate firebase user inside the delete functions try-catch as currentUser() always return null AND GoogleSignIn().signOut() didnt work. Maybe a bug.
import 'package:google_sign_in/google_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
//will need to sign in to firebase auth again as currentUser always returns null
//this try-catch block should be inside the function that deletes user
try {
//FirebaseUser user = await _auth.currentUser(); //returns null so useless
//signin to google account again
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn();
GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
//get google credentials
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleSignInAuthentication.idToken,
accessToken: googleSignInAuthentication.accessToken);
//use credentials to sign in to Firebase
AuthResult authResult = await _auth.signInWithCredential(credential);
//get firebase user
FirebaseUser user = authResult.user;
print(user.email);
//delete user
await user.delete();
//signout from google sign in
await _googleSignIn.signOut();
} catch (e) {
print('Failed to delete user ' + e.toString());
}

Firebase GoogleSignIn.signIn() blocking user interaction

I'm using Firebase and when I use await GoogleSignIn.signIn() a modal shadow shows on top of my app blocking user interaction until if finishes its business.
If it's the first time and the user need to fill or pick a credential (email account) that's understandable.
But once the user has registered it's very annoying to open the app and have to wait for it to finish before interacting with the app. My code is all async and nothing from my part is blocking the user interaction.
Everything works well in the background when using other login methods like passwordless login. But when I use GoogleSignIn, it just throws this modal shadow on top of my app and blocks user interaction.
Am I doing something wrong? Maybe I shouldn't be calling GoogleSignIn.signIn() every time the app is opened after the user has already registered? Or is it just as it's supposed to be?
It takes about a second to finish his business but it's enough to annoy and it can take longer depending on the network connectivity. And if the connection fails, it takes about 5 seconds to give up and throw the error.
The way my app is designed there's no reason to hold the user until he has logged in. He can even use my app offline so I'd really like to change this behavior.
EDIT
Here's my sign in code:
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 FirebaseAuth.instance.signInWithCredential(credential)).user;
check for user, if user is not present then signIn
if (FirebaseAuth.instance.currentUser == null) {
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 FirebaseAuth.instance.signInWithCredential(credential)).user;
} else {
user = FirebaseAuth.instance.currentUser;
}

Flutter How to Link Multiple Auth Providers to an Firebase Account?

I am using firebase in my flutter application. In my app user can sign in or register using 3 ways.
Email id and password.
Google
Facebook.
This is my Firebase setting.
This is my user collection.
Now my doubt is that how do I link multiple auth providers for a user having same email id ?
I am storing user's info into User collection with Uid. If I enable multiple account to multiple providers how can I store user's data in same document ?
I have search a lot on google but didn't find proper solution.
For registration with email ID I am using this.
final newUser = await _auth.createUserWithEmailAndPassword(
email: widget.email, password: widget.pass);
Then I am storing user's data into User collection. (In this I have one more form, from where I am getting other data).
Google sign in code
Future<User> signInWithGoogle() async {
// 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 GoogleAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// Once signed in, return the UserCredential
final UserCredential authResult = await _firebaseAuth.signInWithCredential(credential);
final User user = authResult.user;
print('authResult');
print(authResult);
return user;
}
Users are actually allowed to sign in to your app using multiple authentication providers by linking auth provider credentials to an existing user account.
You can follow the documentation here for the process of linking auth provider credentials to an existing user account:
I suggest to also visit the official documentation of Firebase for Flutter.

Sign In Google will stuck on black screen when try to Add Users Flutter

Hi so i try to add firebase auth on my app, so i followed the documentations in here https://pub.dartlang.org/packages/firebase_auth from the plugin creators it self, It works well at first, but then i'm just ecounter an error or bug, its when i'm tried to add users instead of choose users that already login in my device, after add the users it will stuck forever in black sreen like the picture above, it not giving some error message it just stuck there. So is there anyone that already has same issues like me ? is there any solutions for this ? here is my code for handle the sign in
Future<FirebaseUser> _handleSignIn() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
GoogleSignInAccount googleUser = await _googleSignIn.signIn();
GoogleSignInAuthentication googleAuth = await googleUser.authentication;
FirebaseUser user = await _auth
.signInWithGoogle(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
Navigator.of(context).pushReplacementNamed('/HomeScreen');
await prefs.setString('accesToken', googleAuth.accessToken);
await prefs.setString('email', googleUser.email);
await prefs.setString('displayName', googleUser.displayName);
await prefs.setString('photoUrl', googleUser.photoUrl);
return user;
}
Most probably this happens because you have not enabled the Sign-in Method in Firebase Console.
Just enable Required Sign-in Methods and it should work fine.

Resources