1. The Problem
I'm trying to implement simple Facebook and Google Sign-in buttons with Firebase and Flutter, however the Google version is acting very weird. When I print the FirebaseAuth.instance.currentUser() I either get errors or prior Facebook login data.
When I login with Facebook, my account does appear on Firebase, however, the Google login seems to do nothing.
Is this something I messed up in the code below or some incompatibility problem with AndroidX with parts of these libraries? Something else?
Also, it is not very clear to me if I have to put the Project public-facing name somewhere inside my project to make the integration with Firebase work (I had to do something similar to setup the Facebook Login button).
2. The Facebook Login
I had to replace logInWithReadPermissions with signInWithCredential because recent versions have changed their API. I've also tried to use previous versions of the packages, but encountered many errors (probably due to AndroidX):
final _auth = FirebaseAuth.instance;
Future<FirebaseUser> _loginWithFacebook () async {
final facebookLogin = FacebookLogin();
final result = await facebookLogin.logInWithReadPermissions(['email']);
if (result.status == FacebookLoginStatus.loggedIn){
final FacebookAccessToken accessToken = result.accessToken;
AuthCredential credential = FacebookAuthProvider.getCredential(
accessToken: accessToken.token,
);
AuthResult signInResult = await _auth.signInWithCredential(credential);
FirebaseUser fbUser = signInResult.user;
return fbUser;
}
else{
return null;
}
}
3. The Google Login
Again, signInWithCredential seems to be the more recent API:
Future<FirebaseUser> _loginWithGoogle () async{
final GoogleSignIn _googleSignIn = GoogleSignIn();
GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
AuthResult signInResult = await _auth.signInWithCredential(credential);
final FirebaseUser user = signInResult.user;
print(user);
return user;
}
Edit
I've tried it on an Android 9.0 (Pie) emulator and it still doesn't work.
Apparently, my authentication code was correct for both Google and Facebook, considering the most up-to-date API.
However I needed to integrate a SHA1 Fingerprint to my Firebase environment, which is something I didn't realize I needed to do because none of the tutorials I followed mentioned it and it can be easily dismissed when enabling the Google Sign-in method inside Firebase.
Anyway, here are the steps you will need to complete to get the SHA1 Fingerprint:
Open Command Prompt and cd C:\Program Files\Android\Android Studio\jre\bin.
Get the SHA1 key:
keytool -list -v -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore
Go to Firebase Console > Project settings > Add Key and add the key.
Related
I am running into issue trying to signin to Firebase with Google Sign-in in my Flutter app.
I've seen two other posts about this, but no answers that resolve it for myself. I am using Google Sign-in provider in flutter, google_sign_in: ^5.1.0, Flutter ver 2.2.1
I have followed the instructions on generating/adding the Sha-1, Sha-256 keys to my firebase project. Prior to that , I was getting an API exception. I added the keys, downloaded the latest google-json file to my android folder and got beyond that error. Now, when I click to Sign-in, I get the account selection screen.
I select my account, and then I hit a white page with endless spinner.
Here is the login code I'm running.
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: <String>[
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
Future<void> _handleGoogleSignIn() async {
try {
GoogleSignInAccount? googleSignInAccount =
await _googleSignIn.signIn();
GoogleSignInAuthentication? googleSignInAuthentication =
await googleSignInAccount?.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication?.accessToken,
idToken: googleSignInAuthentication?.idToken,
);
final UserCredential user = await _auth.signInWithCredential(credential);
} catch (error) {
print('in error block');
print(error);
}
}
In doing some debug, it doesn't seem to get beyond the initial line:
GoogleSignInAccount? googleSignInAccount =
await _googleSignIn.signIn();
But I don't get any error, any warning, nothing...just a spinner that sits indefintely.
Any ideas on how to solve this, or at minimum , debug this without getting an error?
Thx
After digging further, I found he answer on the same bug reported on the Flutter github account.
https://github.com/flutter/flutter/issues/89169
The solution:
In the following code snippet (which is defined as default setup)
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
Change https://www.googleapis.com/auth/contacts.readonly (restricted scope) to https://www.googleapis.com/auth/userinfo.profile (non-restricted scope).
After that, OAuth screen will proceed with sign in.
I am working on a flutter app where after sign-in, I have to validate a user's idToken on a custom backend (written in Go) using the Firebase admin SDK: firebase.google.com/go.
I am using the following snippet to sign-in the user via GoogleSignIn and retrieve the Firebase idToken on the client side:
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<String> signInWithGoogle() async {
await Firebase.initializeApp();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final UserCredential authResult = await _auth.signInWithCredential(credential);
final User user = authResult.user;
String FirebaseIdToken = await _auth.currentUser.getIdToken();
print("FirebaseIdToken: " + FirebaseIdToken);
if (user != null) {
/* code to validate user and return it */
} return null;
}
I copy the token corresponding to the FirebaseIdToken variable and send it to the backend using Postman with a Authentication: Bearer <token> request header.
At the backend, there is the following:
/* am.cli here is basically the auth.Client in firebase admin SDK and clientToken is the token received from flutter app. */
idToken, err := am.cli.VerifyIDToken(context.Background(), clientToken)
log.Println("ERROR:", err)
I get the following error printed:
ERROR: failed to verify token signature
Based on the documentation for both client & backend, I believe that I'm using the correct methods to retrieve and to verify the token.
I have tried to retrieve the idToken with the following code as well:
IdTokenResult idTokRes = await _auth.currentUser.getIdTokenResult(true);
print("idTokRes: " + idTokRes.token);
But this fails the same way. (And idTokRes.token and the FirebaseIdToken from the previous method are not same.)
I have also tried to verify the token manually on https://jwt.io/ with the public certificate and the private key which fails as well.
Any help would be appreciated!
Thanks to a member of the Flutter community, I was able to solve the problem.
Turns out, for some reason, the FirebaseIdToken printed by
print("FirebaseIdToken: " + FirebaseIdToken);
is not the complete token. Because of being large, the output gets truncated.
(Still not sure why though. Does Dart's print() statement truncate large strings?)
Edit: Apparently, its the terminal window that truncates/wraps a large output by embedding linebreaks to it.
But, by using the following snippet
String firebaseIdToken = await user.getIdToken();
while (firebaseIdToken.length > 0) {
int startTokenLength =
(firebaseIdToken.length >= 500 ? 500 : firebaseIdToken.length);
print("TokenPart: " + firebaseIdToken.substring(0, startTokenLength));
int lastTokenLength = firebaseIdToken.length;
firebaseIdToken =
firebaseIdToken.substring(startTokenLength, lastTokenLength);
}
I was able to print the complete token in 3 broken parts, which I then concatenated, and sent to the backend via Postman and got no errors this time.
Thanks Rexford!
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
I want support social login with firebase auth. But I want to keep user's detailed profiles in my own RDB .
I thought that after user signed in with social account I could get encoded token which contains user's id and email.
And then if I send the token to the REST server (I built it with spring boot), then the server can decode it to load user's detailed profile from RDB.
I followed the guide from this article.
https://blog.codemagic.io/firebase-authentication-google-sign-in-using-flutter/
I can see sign in process successfully done and the id token printed at the console.
the flutter(dart) code is below.
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final AuthResult authResult = await _auth.signInWithCredential(credential);
final FirebaseUser user = authResult.user;
name = user.displayName;
email = user.email;
imageUrl = user.photoUrl;
final FirebaseUser currentUser = await _auth.currentUser();
await currentUser.getIdToken().then((value) => print(value.token));
I copied the token into the server modult to test it could be decoded with no problem.
I added firebase-admin dependency. and run it with java code below.
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setDatabaseUrl("https://test-firebase-auth-token.firebaseio.com")
.build();
FirebaseApp.initializeApp(options);
String firebaseToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImQ1OThkYjVjZ..."; // actually it's long string.
FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(firebaseToken);
System.out.println(decodedToken.getUid());
System.out.println(decodedToken.getEmail());
And I got an error.
Exception in thread "main" com.google.firebase.auth.FirebaseAuthException: Failed to verify the signature of Firebase ID token. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
at com.google.firebase.auth.FirebaseTokenVerifierImpl.checkSignature(FirebaseTokenVerifierImpl.java:154)
at com.google.firebase.auth.FirebaseTokenVerifierImpl.verifyToken(FirebaseTokenVerifierImpl.java:92)
at com.google.firebase.auth.FirebaseAuth$4.execute(FirebaseAuth.java:426)
at com.google.firebase.auth.FirebaseAuth$4.execute(FirebaseAuth.java:423)
at com.google.firebase.internal.CallableOperation.call(CallableOperation.java:36)
at com.google.firebase.auth.FirebaseAuth.verifyIdToken(FirebaseAuth.java:388)
at com.google.firebase.auth.FirebaseAuth.verifyIdToken(FirebaseAuth.java:362)
at com.example.demo.DemoApplicationTests.main(DemoApplicationTests.java:36)
I tried it again with firebase-server-sdk dependency instead of firebase-admin.
And I got an another error message. (seems that it caused by same reason with above error message)
Caused by: com.google.firebase.auth.FirebaseAuthException: Token isn't signed by a valid public key
at com.google.firebase.auth.internal.FirebaseTokenVerifier.verifyTokenAndSignature(FirebaseTokenVerifier.java:61)
at com.google.firebase.auth.FirebaseAuth$1.call(FirebaseAuth.java:146)
at com.google.firebase.auth.FirebaseAuth$1.call(FirebaseAuth.java:140)
at com.google.firebase.tasks.Tasks$1.run(Tasks.java:63)
I checked the token on this site.
https://jwt.io/
I wonder the token is really signed with a (private) key?
Then how jwt.io site decode it without knowing the key?
It seems like it is just encoded with open algorithm like base64. Isn't it?
If so... the token is not secure any more.
What's the problem with my application. or Do I have miss-conception on security?
Any comment will be welcomed. Thanks...
As answered here, problem on print method. It has limited to ~1024 symbols.
You can print like this:
final idToken = await firebaseCredential.user!.getIdToken(true);
print(idToken.substring(0, 1000));
print(idToken.substring(1000));
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.