Flutter can't get data from Google API - firebase

I'm trying to access the Google People API to get some user data such as name, email, and so on. I used the google_sign_in plugin and firebase_auth to log the user in via the Google Sign-in and I would then like to get his data mentioned up there and simply save it to my database. The problem is that nothing what I tried seems to work and I can't really find much more about this. Also is it true that You now have to use google_sign_in with firebase_auth and can't just use it without Firebase? Because I only need to userData from the People API.
Some "solutions" I found on stack aren't working, one of them beeing How to use Google API in flutter?
I have also tried using this code https://github.com/flutter/plugins/blob/master/packages/google_sign_in/example/lib/main.dart but it's without Firebase and I've seen people say that You now have to use it together with Firebase.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis/people/v1.dart';
import 'package:http/http.dart'
show BaseRequest, IOClient, Response, StreamedResponse, get;
import 'package:http/io_client.dart';
import 'package:google_sign_in/google_sign_in.dart'
show GoogleSignIn, GoogleSignInAccount;
import 'package:googleapis/people/v1.dart'
show ListConnectionsResponse, PeopleApi;
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn(
scopes: <String>['https://www.googleapis.com/auth/userinfo.profile','https://www.googleapis.com/auth/userinfo.email'],
);
Future<String> signInWithGoogle() async {
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final authHeaders = googleSignIn.currentUser.authHeaders;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final AuthResult authResult = await _auth.signInWithCredential(credential);
final FirebaseUser user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
return 'signInWithGoogle succeeded: $user';
}
void signOutGoogle() async{
await googleSignIn.signOut();
print("User Sign Out");
}
class GoogleHttpClient extends IOClient {
Map<String, String> _headers;
GoogleHttpClient(this._headers) : super();
#override
Future<StreamedResponse> send(BaseRequest request) =>
super.send(request..headers.addAll(_headers));
#override
Future<Response> head(Object url, {Map<String, String> headers}) =>
super.head(url, headers: headers..addAll(_headers));
}
I except to simply display a Sign In with Google dialog, the user clicks it and I take his data from the People API and send it to my backend and create a user instance from his data. That's basically it :)

I hope you can interpret some code :)
This guy here made a perfect working Google-Login example.
The Google People Api is for the users contacts, so you would need this & this package.
Now need both google_sign_in with firebase_auth?
yes you then link the google sign in with an firebase_auth user through:
await authInstance.signInWithCredential(credential);

Related

Google Sign In current user return null Flutter

I want to integrate my app with Calendar API from Google. And in order to use it, I have to have an AuthClient (which is obtained from _googleSignIn.authenticatedClient();). The problem is, my GoogleSignIn().currentUser always return null and I don't know why. I already use Firebase Auth and Google Sign In.
This is my signInWithGoogle method:
Future signInWithGoogle() async {
try {
await GoogleSignIn().disconnect();
await FirebaseAuth.instance.signOut();
} catch (e) {
print(e.toString());
}
// Trigger the authentication flow
final GoogleSignInAccount? googleUser = await GoogleSignIn(scopes: [CalendarApi.calendarScope]).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,
);
// Once signed in, return the UserCredential
UserCredential result =
await FirebaseAuth.instance.signInWithCredential(credential);
User user = result.user!;
// note: this line always return null and I don't know why
print('current user auth ${GoogleSignIn().currentUser.toString()}');
return _userFromFirebaseUser(user);
}
Did I do something wrong in my code? Any help will be appreciated, thank you!
I also had the issue of GoogleSignIn().currentUser always being null but managed to (finally!) fix it by only initialising GoogleSignIn() once.
For those who want more details: I did this by creating a class called AuthManager that handles everything authentication-related, and making GoogleSignIn one of the parameters required to initialise it (since I'm using Firebase, this was the other parameter):
class AuthManager {
final FirebaseAuth _auth;
final GoogleSignIn _googleSignIn;
AuthManager(this._auth, this._googleSignIn);
Future signInWithGoogle() async {
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
// etc....
}
GoogleSignInAccount? get googleAccount {
return _googleSignIn.currentUser;
}
}
And I initiaised by AuthManager class ONCE at the top of my app in a Provider, meaning that I can access it anywhere in my app.
In main.dart:
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
// To use AuthManager throughout app without initialising it each time
Provider<AuthManager>(
create: (_) => AuthManager(
FirebaseAuth.instance,
GoogleSignIn(scopes:
// Put whatever scopes you need here
),
),
),
// etc...
(Note: I used MultiProvider as I had other things I wanted to put, but if you only have one, you can obviously just go straight to Provider).
Now I can successfully get the current google user by getting googleAccount through my AuthManager class.

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());
}

Flutter web google sign in - the popup doesn't show, sign in button does nothing

I have a Flutter web app which uses Google sign in, managed with Firebase. If I run it with flutter run -d chrome, when I click on the sign in button, it pops up the Google sign in pane, however after writing in my email address, it says that it's an unsafe browser and that I should try to use another browser. After some research, I founda workaround, opening the localhost:5000 from a separate chrome window. In this case, the issue is that it doesn't show the popup.
I don't know if it has to do anything with the issue, but when I inspect the element it shows this warning:
The code I use to handle the sign-in:
import "package:firebase_auth/firebase_auth.dart";
import "package:google_sign_in/google_sign_in.dart";
class GoogleSignInService {
final GoogleSignIn _googleSignIn;
final FirebaseAuth _auth;
GoogleSignInService(this._googleSignIn, this._auth);
Future<FirebaseUser> handleSignIn() async {
FirebaseUser user;
bool isSignedIn = await _googleSignIn.isSignedIn();
if (isSignedIn) {
user = await _auth.currentUser();
} else {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken, idToken: googleAuth.idToken);
user = (await _auth.signInWithCredential(credential)).user;
}
return user;
}
}
I call the handlesignin in the onPressed of my sign in button. I use version 4.5.4 of the google_sign_in package. I have done everything suggested here: https://pub.dev/packages/google_sign_in_web

Link Multiple Auth Providers to an Account

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.

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