Firebase facebook and gmail accounts are not merged - java

When i sign in to my android app using gmail and facebook, two separate authentication credentials are created at firebase. Is it possible to merge them?

Sign in the user using any authentication provider or method. (Assume your user have already Signed In with Google).
Get the credentials for the new Authentication Provider (Facebook).
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
Pass the AuthCredential object to the signed-in user's ``linkWithCredential``` method.
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "linkWithCredential:success");
FirebaseUser user = task.getResult().getUser();
updateUI(user);
} else {
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});

Related

Firebase Authentication with Google Play Games

I am creating a game for android. Each user needs to be authenticated.
Currently, when a new user launches the game, it requests an identification code from my server, and stores it to SharedPreferences. Next time user launches the game, it uses this stored identification code to authenticate. The problem is, when user clears data of this app, there's no way he can get his ID back, so he lost his progress forever.
Is there a way how to generate something like Identification code which is unique and always the same for one player using Firebase Play games auth method?
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
.requestServerAuthCode("MyCID")
.build();
mAuth = FirebaseAuth.getInstance();
super.onCreate(savedInstanceState);
final FirebaseAuth auth = FirebaseAuth.getInstance();
AuthCredential credential = PlayGamesAuthProvider.getCredential("MyCID");
auth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
currentUser = auth.getCurrentUser();
} else {
Toast.makeText(MainActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
}
});
if (currentUser == null) {
cu = "NO UID";
} else {
cu = currentUser.getUid();
}
I tried this code (Where is MyCID: I used the CID from the image below), but no Google Play Games pop-up is shown, I get Authentication Failed toast and cu is set to "NO UID".
Can someone explain how does this work please?
EDIT
Thanks to #crysxd , My app now shows the green google play games popup. But instead of expected "Select an account" popup, as I see in other games which uses google games sign in, I get an error, which says "com.google.android.gms.common.api.ApiException: 4:".
Is there a function which I need to run to show this dialog? Am I missing something or just I have incorrectly configured the game in google play console?
My current code: link
You are skipping an essential step here. The Firebase docs are usually very good, but the Play sign in is poorly described.
You got the first step right: You need to set up GoogleSignInOptions but you miss to pass them to a GoogleSignInClient.
Create a client in onCreate:
private static final int RC_SIGN_IN = 543;
private GoogleSignInClient mGoogleSignInClient;
public void onCreate(Bundle savedInstancestate) {
super.onCreate(savedInstancestate)
// ...
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
.requestServerAuthCode("MyCID")
.build();
mGoogleSignInClient= GoogleSignIn.getClient(this, gso)
}
Call this method when the sign in button is clicked or you want to start sign in. This will cause the sign in dialog to be shown.
private void signIn() {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
Get the sign in response and handle it
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from
GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = task.getResult(ApiException.class);
firebaseAuthWithGoogle(account);
} catch (ApiException e) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e);
}
}
}
Finally, your code comes into play. Now we have the GoogleSignInAccount which is required to call PlayGamesAuthProvider.getCredential(...). You passed your Client ID here, but that's the wrong thing. This is how it works: You give your client ID to Google just to tell them who (or which app) you are. They will let the user sign in and give you a special token ("id token") which Firebase can then use to get information about the user from Google Play Games. And that's the token you need to give to Firebase here:
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Snackbar.make(findViewById(R.id.main_layout), "Authentication Failed.", Snackbar.LENGTH_SHORT).show();
updateUI(null);
}
// ...
}
});
}
Hope that helps! You can find the entire code referenced in the docs here and here (these are the files they show the snippets from in the docs).

Firebase user registration with google

I am trying to implement google sign-in feature in my app. I have followed this documentation, problem is - if I use previously used google account, it is not showing an error like "the e-mail is already registered in this app". As a result, previously stored data with the account are deleted & the google account is registered again. Here is my code :
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
int coins = 100;
String name, email;
name = user.getDisplayName();
email = user.getEmail();
//updateUI(user);
storeUserCredentials(name, email, coins);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(SignUpActivity.this, "Error : " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
}
public void storeUserCredentials(String name, String email, int coins){
progressBar.setVisibility(View.VISIBLE);
User user = new User(name, email, coins);
mDatabase.getReference("Users")
.child(mAuth.getCurrentUser().getUid())
.setValue(user)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
progressBar.setVisibility(View.GONE);
if (task.isSuccessful()){
Toast.makeText(SignUpActivity.this, "Registration Successful!", Toast.LENGTH_SHORT).show();
startActivity(new Intent(SignUpActivity.this, MainActivity.class));
finish();
} else {
if (task.getException() instanceof FirebaseAuthUserCollisionException){
Toast.makeText(SignUpActivity.this, "The email is already used", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SignUpActivity.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
});
}
What is wrong with my code, please explain.
When you call signInWithCredential the SDK returns a task that successfully completes when the user is signed in. Since you call storeUserCredentials on that condition, it will get called each time the user is signed in. This is actually a quite normal flow.
If you want to detect if this account is new to Firebase Authentication, you can check the creation time of the user. See Firebase Auth, how to know new user signed up, rather than existing user sign in?
If you want to detect whether you've already seen the user before, you'll want to check in the database before calling storeUserCredentials. But what you now have is a pretty idiomatic flow, since it for example ensures you store the up-to-date display name each time you ask the user to sign in.

Auth all users to Firebase

I have a firebase app for which I don't need or want user signup or login but I want to setup Auth to make sure database can only be accessed through my app. Is there any way to do so?
You can use Anonymous Authentication for that purpose. Users don't need to enter any details for sign up or login, Firebase will simply give them an uid to access your database and you can still keep your Firebase Security Rules set to auth!=null.
Go ahead, add Firebase Auth to your app and then on your Activity:
Grab an instance of the FirebaseAuth Object:
private FirebaseAuth mAuth; mAuth = FirebaseAuth.getInstance();
Sign the user in, anonymously:
mAuth.signInAnonymously()
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>(){
#Override
public void onComplete(#NonNull Task<AuthResult> task){
if(task.isSuccessful()){
Log.d(TAG, "signInAnonymously:success");
}
else
{
Log.w(TAG, "signInAnonymously:failure", task.getException());
Toast.makeText(AnonymousAuthActivity.this, "Failed", Toast.LENGTH_SHORT).show();
}
}
});

Android Firebase Removing all user data with relogin

I'm trying to create users table in Firebase realtime database.However, everytime user re-logins his previously entered data is being removed or overwritten.Couldnt understand how should I change it.
private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(RegisterActivity.this,"Registration Is Succesfull",Toast.LENGTH_LONG).show();
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user=mAuth.getCurrentUser();
final String databaseUserName=user.getDisplayName();
String name=mAuth.getCurrentUser().getDisplayName();
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
//after that user is redirected to the main account activity.
Intent accountIntent = new Intent(RegisterActivity.this,UserAccountActivity.class);
accountIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(accountIntent);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(RegisterActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
// if signing up task is unsuccesfull we do make a error indication pretty much.
FirebaseAuthException e = (FirebaseAuthException )task.getException();
Toast.makeText(RegisterActivity.this, "Failed Registration: "+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("LoginActivity", "Failed Registration", e);
}
}
});
}
So once I run the code, for the very first time it works perfectly fine and say I edit&add additional user info but once the user logs out and re-enters, everything is cleared out and node is again created.
Here you are saving the data in the database:
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
Now on the second time, the data is not getting deleted or cleared, it cannot be deleted magically, the data is getting overridden. All you need to do is add a push() that will create a random id for each log in.
So like this:
DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users").push();
DatabaseReference userNameRef = myRootRef.child(databaseUserName)
Edit:
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(Activity_name_here.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Toast.makeText(getApplicationContext(), "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Authentication failed." + task.getException(),
Toast.LENGTH_SHORT).show();
} else {
Here is the working version of the source code. You can use the very same code for facebook login as well. This code simply prevents user from overwriting when logging in again.
private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(SignInActivity.this,"Registration Is Succesfull",Toast.LENGTH_LONG).show();
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
//getting current users account
FirebaseUser user=mAuth.getCurrentUser();
//getting the display name of the current user to store them in our real time database
final String databaseUserName=user.getDisplayName();
//creating a child called users
final DatabaseReference myRootRef = FirebaseDatabase.getInstance().getReference().child("Users");
//here we make a control such that, if logged in user is exist in the realtime database
//if not exists, then we save them , if exists we continue with the else statement and break it.
myRootRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChild(databaseUserName)){
DatabaseReference userNameRef = myRootRef.child(databaseUserName);
//value is also set to user display name however it doenst have to be so
userNameRef.setValue(databaseUserName);
} else{
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//after that user is redirected to the main account activity.
Intent accountIntent = new Intent(SignInActivity.this,UserAccountActivity.class);
accountIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(accountIntent);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(SignInActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
// if signing up task is unsuccesfull we do make a error indication pretty much.
FirebaseAuthException e = (FirebaseAuthException )task.getException();
Toast.makeText(SignInActivity.this, "Failed Registration: "+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("LoginActivity", "Failed Registration", e);
}
}
});
}

How to verify email id authenticated by Google or not when we signup using the Firebase for android?

When users signup using the Firebase Email/Password SIGN-IN METHOD in android, how can we verify their Emails ?
For Android Email verification, first you can view the documentation by firebase here.
Send a user a verification email
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Email Sent.");
}
}
});
In my App whenever a user registers, sendEmailVerification(); is triggered
private void sendEmailVerification() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Email verification sent.");
}
}
});
}
Using the previous method, your users will now be provided with a verification Email. And it will look something a lot like this
Did they verify their email ?
private void IsEmailVerified() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user.isEmailVerified()) {
Log.d(TAG, "Email is verified.");
} else {
Log.d(TAG, "Email is not verified !.");
}
}
Sadly, you may not customize the content/body of your verification Email ( I have been heavily corresponding with Firebase to provide alternative less hideous looking templates ). You may change the title or the message sender ID, but that's all there is to it.
Not unless you relink your application with your own supported Web. Here.

Categories

Resources