GitHub Authentication for Android Through Firebase - java

Hello I want to know how can I access user email while authenticating a user through Github in my android App. I am using firebase and android studio. Please note that I cannot use user.getEmail in onSuccesslistner because I am also using Google authentication, which throws exception that email already exist and pending task method works for first time only. Basically I want to use setScopes to retrieve the user Email. I have to get Email and check if user exist in my database in simply logged in user.
Here is my Code:
public void git_login(View view)
{
SignInWithGithubProvider(
OAuthProvider.newBuilder("github.com")
.setScopes(
new ArrayList<String>()
{
{
add("user:email");
}
}).build()
);
}
private void SignInWithGithubProvider(OAuthProvider login)
{
Task<AuthResult> pendingResultTask= mAuth.getPendingAuthResult();
if (pendingResultTask!=null)
{
// There's something already here! Finish the sign-in for your user.
pendingResultTask
.addOnSuccessListener(
new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
Toast.makeText(getApplicationContext(), "User Exist" + authResult, Toast.LENGTH_SHORT).show();
// User is signed in.
// IdP data available in
// authResult.getAdditionalUserInfo().getProfile().
// The OAuth access token can also be retrieved:
// authResult.getCredential().getAccessToken().
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Handle failure.
}
});
}
else {
// There's no pending result so you need to start the sign-in flow.
// See below.
mAuth.startActivityForSignInWithProvider(this , login).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e)
{
if (e.toString().equals("com.google.firebase.auth.FirebaseAuthUserCollisionException: An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address."))
{
showDialogAlert();
}
}
}).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
FirebaseUser user = mAuth.getCurrentUser();
Toast.makeText(getApplicationContext(), "Login" + user.getUid() +"\n"+user.getEmail(), Toast.LENGTH_SHORT).show();
userNameForDb = user.getDisplayName();
userImageForDb = String.valueOf(user.getPhotoUrl());
userEmailForDb = user.getEmail();
Toast.makeText(CreateNewAccountActivity.this, "Account added to Firebase: " +userNameForDb+"\n"+userEmailForDb+"\n"+userTokenForDb, Toast.LENGTH_SHORT).show();
saveDataToDb(userNameForDb , userEmailForDb , userTokenForDb);
}
});
}
}
```

I want to know how can I access user email while authenticating a user through Github
The simplest solution I can think of is once you are successfully authenticated, you can get the email address from the "userInfo" object like in the following lines of code:
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (firebaseUser != null) {
for (UserInfo userInfo : firebaseUser.getProviderData()) {
if (userInfo.getProviderId().equals("github.com")) {
Log.d(TAG, "User is signed in with Github");
Log.d(TAG, "email: " + userInfo.getEmail());
}
}
}
The output in the logcat will be the email address that was used by the user for the authentication process.
Edit:
It's true, if the user is already registered with a Gmail account, you'll get an Exception that says that such an account is already there. So you need to use for authentication Google credentials.
I actually want to get the user id in this case and want to check it in my database which is my local server that this email exists or not.
There is no need for that because you can handle the Exception, and indicate to the user that a Google account is already there, and then simply use Google credentials for authentication. If there is no Exception, is obvious that the user doesn't exist yet.

Related

FirebaseUser password not updating through updatePassword() method in android

I am trying to update or reset the user's password in my Android application using Firebase Authentication. For this, I am using the updatePassword() method provided by FirebaseUser class, but it is throwing the code in addOnFailureListener() and I am unable to figure out why. please help me. I have provided the code to update the password below:
updatePasswordButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String newPassword = enterPasswordEditText.getText().toString().trim();
String confirmPassword = confirmPasswordEditText.getText().toString().trim();
if (!newPassword.equals(confirmPassword)) {
Toast.makeText(EditProfileActivity.this, "Passwords don't match!", Toast.LENGTH_SHORT)
.show();
} else {
//Updating password
firebaseUser.updatePassword(newPassword)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void unused) {
Toast.makeText(EditProfileActivity.this, "Password changed successfully", Toast.LENGTH_SHORT)
.show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(EditProfileActivity.this, "Error in changing password", Toast.LENGTH_SHORT)
.show();
}
});
}
}
});
You're getting the following error:
Error in changing password: This operation is sensitive and requires recent authentication. Log in again before retrying this request
Because changing the password is considered a sensitive operation. This means that in order to perform that operation, Firebase requires that the user has recently signed in.
If the user hasn't recently signed in, meaning that 5 minutes have already passed, when you try to perform such a sensitive operation, Firebase throws an exception that contains the error message from above.
The simplest solution for this situation would be to ask the user to re-enter their credentials and retry the operation.
Here is the official documentation for FirebaseAuthRecentLoginRequiredException.

Fireabase Realtime Database client requests have expired, I have re enabled them, but still entries are not created in the db?

I am working on an android app for my degree and I am using Firebase Realtime Database, the app is going to be something similar to spotify, but on a smaller scale. I was forced to take a longer break and my client requests from the Database have been automatically disabled (the 30 day limit by default).
I've changed the rules to be "true" for both read and write(for the purpose of making it work, not secure, I will change them appropriately). I also attached some screenshots and code snippets to help. I checked other stack questions and they didnt help, the only solution I see right now is making another project so basically reinitializing the whole thing withing a new Firebase project.
private void registerUser(){
final String email = emailField.getText().toString().trim();
final String username = usernameField.getText().toString().trim();
String password = passwordField.getText().toString().trim();
String confirmPass = confirmPasswordField.getText().toString().trim();
if(username.isEmpty()){
usernameField.setError("Username is required");
usernameField.requestFocus();
return;
}
if(email.isEmpty()){
emailField.setError("Email is required");
emailField.requestFocus();
return;
}
if(password.isEmpty()){
passwordField.setError("Password is required");
passwordField.requestFocus();
return;
}
if(!Patterns.EMAIL_ADDRESS.matcher(email).matches()){
emailField.setError("Please provide valid email");
emailField.requestFocus();
return;
}
if(password.length() < 6){
passwordField.setError("Password length should be at least 6 characters");
passwordField.requestFocus();
return;
}
if(!password.equals(confirmPass)){
confirmPasswordField.setError("Passwords do not match");
confirmPasswordField.requestFocus();
return;
}
progressBar.setVisibility(View.VISIBLE);
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
User user = new User(username, email);
FirebaseDatabase.getInstance().getReference("Users")
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.setValue(user).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Toast.makeText(RegisterActivity.this, "User has registered successfully", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(RegisterActivity.this, "Registration has failed", Toast.LENGTH_LONG).show();
}
progressBar.setVisibility(View.GONE);
}
});
}
}
});
}
This is where I register my user to the Realtime Database. They do show up in the authentication tab and I can log in with them, but they do not in the database.
{
"rules": {
"users": {
".read": "true",
".write": "true",
}
}
}
These are the rules that I am using right now with the purpose of getting to the bottom of this issue that I am having right now, I am planning to change them so that the users can only write data that belongs to them.
Basically my question boild down to, if my client requests have expired, what can I do to re enable them so that I can have entries in my Realtime DB again? This is the DB right now

Is there a way to restrict Google Sign In to a certain email domain in Android?

Is there a way to restrict Google signIn in the app to certain emails with domain #companyname.com?
The goal is to let only #companyname.com users only to gain access in the log in features.
I have done some research but I have come up with nothing yet.
You Need To Check This After Signing In That Will Be A Secure Way To Do It
private void handleSignInResult(GoogleSignInResult result) {
Log.d(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// Signed in successfully.
GoogleSignInAccount acct = result.getSignInAccount();
String email = acct.getEmail();
String[] split = s.split("#");
String domain = split[1]; //This Will Give You The Domain After '#'
if(domain.equals("companyname.com"))
{
//Proceed Ahead.
}
else
{
//Show User Warning UI.
}
} else {
// Signed out, show unauthenticated UI.
updateUI(false);
}
}

How to initialize firebase after android google login?

I wanted to try and keep my native android firebase development to minimum so as to when I'm ready to port to IOS/web I won't be doing a lot there.
Right now firebase's Javascript doesn't allow google login from Android, this can be taken care of from the plugin. But what I'm stuck on is how to initialize firebase based on the Java Android Google login.
So this is what I'm trying to achieve:
Cordova calls Java-Android-Native login into google ---> based on this, how would I initialize firebase?
This plugin can let me login into google natively: https://www.npmjs.com/package/cordova-plugin-googleplus
But I guess I need auth token? token ID?
firebase.auth().signInWithCredential(credential).catch(function(error) {
} else {
console.error(error);
}
});
Can this give me the above required toke? https://developers.google.com/identity/sign-in/android/sign-in
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
Update 1: Just want to share more information. When getting the user logged in through google on android I have the below object
GoogleSignInAccount
https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInAccount
It has public String getIdToken () & public String getServerAuthCode () why can't these be used to authenticate firebase using JS?
Update 2: Answer provided by Faraz seems to be working. Here is reference for the function signInWithCredential https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signInWithCredential
Thank you for your help.
Use auth.signInWithCredential with the GoogleAuthProvider credential.
Here is an example:
auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential(googleAccessToken)).then(function(user) {
// Google User is logged in
}).catch(function(error) {
// Error
});
Source for more infomation
You can read this GitHub example about Firebase usage.
And Here you can find -
mFirebaseRef.authWithOAuthToken("google", token, new AuthResultHandler("google"));
Which (if all is success) calls this
public void onAuthenticated(AuthData authData)
Where token is your getIdToken
I mean it is possble to login into Firebase using Google, Facebook,Twitter in all cases you have to send token you receive to Firebase server that checks your token whether you already logged in or not. You can setup your own server in the same way.
After google login you have to Use auth.signInWithCredential with the GoogleAuthProvider credential:
Here is an code:
private void firebaseAuthWithGoogle(GoogleSignInAccount account) {
Log.d(TAG, "firebaseAuthWithGoogle:" + account.getId());
final String name = account.getDisplayName();
final String email = account.getEmail();
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
getAuth().signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "onComplete: sign in with credentials " + task.isSuccessful());
if (task.ienter code heresSuccessful()) {
Log.e(TAG, "success: sign in with credentials ");
}
if (!task.isSuccessful()) {
Log.e(TAG, "onComplete: sign in with credentials " + task.getException());
}
}
});
}

Parse Google plus login

I am using Parse, where are users are able to login using Facebook, Twitter, and Google+. As of now, only Facebook and Twitter is fully functional.
I have managed to login using Facebook and Twitter in the following way:
private void onLoginButtonClicked() {
LoginActivity.this.progressDialog = ProgressDialog.show(
LoginActivity.this, "", "Logging in...", true);
List<String> permissions = Arrays.asList("public_profile", "user_about_me",
"user_relationships", "user_birthday", "user_location");
ParseFacebookUtils.logIn(permissions, this, new LogInCallback() {
#Override
public void done(ParseUser user, ParseException err) {
LoginActivity.this.progressDialog.dismiss();
if (user == null) {
Log.d(IntegratingFacebookTutorialApplication.TAG,
"Uh oh. The user cancelled the Facebook login.");
} else if (user.isNew()) {
Log.d(IntegratingFacebookTutorialApplication.TAG,
"User signed up and logged in through Facebook!");
showUserDetailsActivity();
} else {
Log.d(IntegratingFacebookTutorialApplication.TAG,
"User logged in through Facebook!");
moodpage();
}
}
});
}
private void onTwitterButtonClicked() {
ParseTwitterUtils.logIn(this, new LogInCallback() {
#Override
public void done(ParseUser user, ParseException err) {
if (user == null) {
Log.d("MyApp", "Uh oh. The user cancelled the Twitter login.");
} else if (user.isNew()) {
Log.d("MyApp", "User signed up and logged in through Twitter!");
showUserDetailsActivity();
} else {
Log.d("MyApp", "User logged in through Twitter!");
moodpage(); }
}
});
}
I am trying to figure out to achieve this with Google+ through parse. Someone has suggested for me to look into Parse Rest API, however, I am not familiar with it, and need more guidance.
Any clarification will be appreciated.
as per this:
http://blog.parse.com/announcements/adding-third-party-authentication-to-your-web-app/
and this:
https://parse.com/tutorials/adding-third-party-authentication-to-your-web-app
And my understanding of them
You just need to generate a password using some algorithm in your app or your cloud/backend, after successfully logging in with Google+ / Github / Whatever
a simeple implementation (but it's not secured to have it in your app):
// given Google Plus login (Using their Api) i.e. no Parse yet at this point
int id = 12345; // assume that this is google+ id (After successfully logging in)
ParseUser user = new ParseUser();
user.setUsername("google-plus-" + String.valueOf(id));
user.setPassword(hashMyPassword(id)); // Create password based on the id
user.setEmail("email.from.google.plus.login#gmail.com");
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
// Hooray! Let them use the app now.
} else {
// Sign up didn't succeed. Look at the ParseException
// to figure out what went wrong
}
}
});
One important thing about this solution:
It's not secured to just use the id / password based on the id in your app, a better solution would be to send Google+ Token / UserId to backend/cloud then the Backend/Cloud verifies that this Token/Id are valid, then create the username/password out of it and exchange it with Parse User.
I hope you got the Idea.

Categories