Google_sign_in Org_internal unable to login with different account - flutter

I'm working on an application for my organization. I was trying to implement oAuth with the google_sign_in package based on our google accounts.
The process for members to log in with accounts that belongs to the organization works fine. That's not the case with external emails.
I was expecting an error to be thrown in google prompt but I'm unable to log in with different at all. Seams that google tries to log me in instantly each time, leading to this screen each time:
I've tried using GoogleSignIn().signOut() or .deactivate() methods both of those did nothing to either remove the cache or retrigger the signing process.
Code responsible for log in:
class FirebaseAuthExternalIdentityProvider implements ExternalIdentityProvider {
final FirebaseAuth _firebaseAuth;
FirebaseAuthExternalIdentityProvider({required FirebaseAuth firebaseAuth})
: _firebaseAuth = firebaseAuth;
#override
Future<Result<GoogleSignInTokenWrapper>> signInWithGoogle() async {
final GoogleSignInAccount? googleAccount = await GoogleSignIn().signIn();
if (googleAccount == null) {
return Result.failure(Failure.signInProcessAborted());
}
final GoogleSignInAuthentication? googleAuthStatus =
await googleAccount.authentication;
final OAuthCredential _firebaseCredential = GoogleAuthProvider.credential(
accessToken: googleAuthStatus?.accessToken,
idToken: googleAuthStatus?.idToken,
);
try {
return Result.success(GoogleSignInTokenWrapper(
accessToken: await (await _firebaseAuth
.signInWithCredential(_firebaseCredential))
.user!
.getIdToken(),
));
} on FirebaseAuthException catch (cause) {
return Result.failure(Failure.firebaseSignInException(cause: cause));
} on Exception catch (cause) {
return Result.failure(Failure.unexpected(cause: cause));
}
}
}
Does someone know how to handle this problem? Changing the OAuth consent screen to External is the last thing I want to consider doing.
Thanks for any help in this matter!

Related

how to keep user logged in

this is how I login using Google and firebase. but I couldn't figure it out as to how to keep the use logged in.. when the app restarts it log the user out automatically
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<String> signInWithGoogle() async {
final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount!.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final authResult = await _auth.signInWithCredential(credential);
final User? user = authResult.user;
assert(!user!.isAnonymous);
final User? currentUser = _auth.currentUser;
assert(user!.uid == currentUser!.uid);
return 'signInWithGoogle succeeded: $user';
}
You can call await _auth.currentUser() at the start of your app to check the current user. Further you may want to store the token in shared preferences.
Firebase automatically persists the user credentials in the shared storage, and restores them when the app restarts. There's nothing you need to do for that.
What you will need to do though is listen for the authentication state as shown in the first code snippet in the documentation on getting the current user:
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user != null) {
print(user.uid);
}
});
This code needs to run when the app starts, so I typically have it in my top-level widget and then store the user in the state so that my build method can use it. By listening to auth state changes, the code is run automatically when the user sign-in state is restored at startup (which happens asynchronously, so may take a few moments) but also when the user would later be logged out (for example, if you disable the account in the Firebase Authentication console).
It may not be the best way to do it but this worked.
chooseLogin() {
if (_auth.currentUser == null) {
return const SignUo();
} else {
return const Splash();
}
}

Error getting thrown when trying to sign in with Google Auth to Firestore

I am trying to create a google sign in option for my app. I appear to be getting back a valid Token Id from google but my app is crashing in the ios Emulator and the following error is being shown in console.
flutter: [firebase_auth/invalid-credential] Unable to parse Google id_token: ya29.A0ARrdaM_uqbYHorJh1kJXTXac7MEm2TjD.......
When I cancel the login an error is successfully being thrown from my code. Can anyone help me out?
flutter: [firebase_auth/sign_in_canceled] The user canceled the sign-in flow.
#override
Future<User?> signInWithGoogle() async {
final googleSignIn = GoogleSignIn();
final googleUser = await googleSignIn.signIn();
if (googleUser != null) {
final googleAuth = await googleUser.authentication;
if (googleAuth.idToken != null) {
final UserCredential = await _firebaseAuth
.signInWithCredential(GoogleAuthProvider.credential(
idToken: googleAuth.accessToken,
));
return UserCredential.user;
} else {
throw FirebaseAuthException(
code: 'ERROR_MISSING_GOOGLE_ID_TOKEN',
message: 'Missing Google ID Token',
);
}
} else {
throw FirebaseAuthException(
code: 'sign_in_canceled',
message: 'The user canceled the sign-in flow.',
);
}
}
I figured it out. This line needed to be changed to pass the idToken...not the accessToken.
idToken: googleAuth.idToken,

linkWithCredential and Flutter Web with Apple

I have a use case where a user, on Flutter Web, needs to link an Apple auth with their existing account, and the email may not match.
However, the only available method for Flutter Web Apple Authentication is signInWithPopUp. If the user's apple email is different from the User firebase account email, a new firebase account is created, and a user is returned, short circuiting the process of linking, this creates a new account in firebase, and I'm unable to linkWithCredential.
My method to try to link accounts is as follows:
Future<String> linkWithAppleWeb() async {
try {
final User user = _auth.currentUser!;
final provider = OAuthProvider("apple.com")
..addScope('email')
..addScope('name');
await _auth.signInWithPopup(provider).then((appleCredential) async {
final authCredential = appleCredential.credential;
await user.linkWithCredential(authCredential!).then((result) {
DatabaseService().updateUserSocialAuth(user.uid, 'apple');
return 'Success';
}).catchError((e) {
return 'Error: $e';
});
});
} catch (e) {
return 'Error: $e';
}
return 'Success';
}
As you would expect, my project starts with Streaming a User Object, and when the pop up signs in, it returns the new user, which rebuilds the entire project. Is there a way to authenticate an apple user without returning a new user? I can link a google or phone authorization method fine. It's apple that is problematic. I don't fully understand why Google doesn't break in the same way, other than Firebase put in the work to ensure the functionality of linking for GoogleSignIn().signIn() I'm not using other social auth methods, and I don't use password/email.
This method is not documented in the Flutter Fire Docs, but works perfectly:
Future<String> linkWithAppleWeb() async {
try {
final User user = _auth.currentUser!;
final provider = OAuthProvider("apple.com")
..addScope('email')
..addScope('name');
await user.linkWithPopup(provider).then((result) {
DatabaseService().updateUserSocialAuth(user.uid, 'apple');
return 'Success';
}).catchError((e) {
return 'Error: $e';
});
} catch (e) {
debugPrint('auth linkWithGoogle error: ${e.toString()}');
return 'Error: $e';
}
return 'Success';
}

What is causing the unexpected number of firestore reads based on the architecture of my app? [duplicate]

there guys, I do have an interesting problem here and I would be really glad if any of you it will be able to help me with that.
What's my app flow:
Register with the email, password and some other details:
User firebase in order to auth the user and create an account via email and password, at the same time I'm writing the custom data of the user to the database.
Log in the user.
That's it, that's all my basic logic, and how you can see I'm not doing any reading from the DB so far as I know.
Now... the problem is that from some weird reason when I'm registering my user I'm going to the firebase console to see the usage of my DB and I will see something like... for one user which was created I will have 1 write (which is fine as I was expected) but also 13-20 READS FROM DB.
Now that's my question, WHY on earth I have reads on firestorm when I'm doing just auth and writes?
Here it's my DB code which I'm using right now.
class DatabaseFirebase implements BaseDataBase {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseStorage _storage = FirebaseStorage.instance;
FirebaseUser _firebaseUser;
Firestore _firestore = Firestore.instance;
#override
Future<String> login(String email, String password) async {
_firebaseUser = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
return _firebaseUser.uid;
}
#override
Future<String> register(String email, String password) async {
_firebaseUser = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
return _firebaseUser.uid;
}
#override
Future<UserData> getCurrentUser() async {
if (_firebaseUser == null)
_firebaseUser = await _firebaseAuth.currentUser();
UserData user = UserData();
user.email = _firebaseUser?.email;
user.name = _firebaseUser?.displayName;
return user;
}
#override
Future<void> logout() async {
_firebaseAuth.signOut();
}
#override
Future<void> onAuthStateChanged(void Function(FirebaseUser) callback) async {
_firebaseAuth.onAuthStateChanged.listen(callback);
}
#override
Future<void> writeUser(UserData user) async {
_firestore.collection("Users").add(user.toMap()).catchError((error) {
print(error);
});
}
}
If some of you know could you explain to me where/how I need to search in order to find this bug? Because how you can see I'm not using any read what so ever.
It's impossible to know for sure given that we don't understand all possible routes of access into your database, but you should be aware that use of the Firebase console will incur reads. If you leave the console open on a collection/document with busy write activity, the console will automatically read the changes that update the console's display. This is very often the source of unexpected reads.
Without full reproduction steps of exactly all the steps you're taking, there's no way to know for sure.
Firebase currently does not provide tools to track the origin of document reads. If you need to measure specific reads from your app, you will have to track that yourself somehow.

How to connect facebook, firebase and flutter?

I'm following the instructions for incorporating facebook with android projects found here https://developers.facebook.com/apps/318154048893918/fb-login/quickstart/ and there is a step to download the Facebook SDK, but after that, it doesn't tell me where to put the file. The import statement it tells me to add won't work (says target of uri doesn't exist).
I'm trying to add the facebook user to our firebase database when they log in. I'm using flutter in android studio.
There doesn't seem to be anything of use in the console log, except that print statement doesn't print anything. Any ideas?
Here's my code to log in the user.
import com.facebook.FacebookSdk;
import com.facebook.appevents.AppEventsLogger;
Future<FirebaseUser> initiateFacebookLogin() async {
final FacebookLoginResult result =
await facebookLogin.logInWithReadPermissions(['email', 'public_profile']);
FirebaseUser user =
await _auth.signInWithFacebook(accessToken: result.accessToken.token);
//Token: ${accessToken.token}
ProviderDetails userInfo = new ProviderDetails(
user.providerId, user.uid, user.displayName, user.photoUrl, user.email);
List<ProviderDetails> providerData = new List<ProviderDetails>();
providerData.add(userInfo);
print(user.displayName);
addToDatabase(user.uid, user.displayName, user.displayName, user.email);
return user;
}
In flutter you need use flutter_facebook_login plugin take a look here to see how to get the plugin and setup your flutter app to make use of this plugin. You can also check this article that is step-by-step about how setup you project and contains code example too but the API used is out of date.
Here a snippet with updated API showing how to achieve login in firebase with facebook account.
/// This mehtod makes the real auth
Future<FirebaseUser> firebaseAuthWithFacebook({#required FacebookAccessToken token}) async {
AuthCredential credential= FacebookAuthProvider.getCredential(accessToken: token.token);
FirebaseUser firebaseUser = await _authInstance.signInWithCredential(credential);
return firebaseUser;
}
In your code you're using _auth.signInWithFacebook method that is deprecated and you should replaced by signInWithCredential updating you firebase_auth plugin version.
///This object comes from facebook_login_plugin package
final facebookLogin = new FacebookLogin();
final facebookLoginResult = await facebookLogin
.logInWithReadPermissions(['email', 'public_profile']);
switch (facebookLoginResult.status) {
case FacebookLoginStatus.error:
print("Error");
break;
case FacebookLoginStatus.cancelledByUser:
print("CancelledByUser");
break;
case FacebookLoginStatus.loggedIn:
print("LoggedIn");
/// calling the auth mehtod and getting the logged user
var firebaseUser = await firebaseAuthWithFacebook(
token: facebookLoginResult.accessToken);
}
}