16

I am using Firebase Authentication for my Android app. Users have the ability to login with multiple providers (Google, Facebook, Twitter).

After a successful login, is there a way to get the user gender/birth date from these providers using the Firebase api?

TareK Khoury
  • 12,721
  • 16
  • 55
  • 78

4 Answers4

4

Unfortunately, Firebase doesn't have any built-in functionality to get the user's gender/birthdate upon successful login. You would have to retrieve these data from each of the providers yourself.

Here is how you might get the user's gender from Google using Google People API

public class SignInActivity extends AppCompatActivity implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        View.OnClickListener {
    private static final int RC_SIGN_IN = 9001;

    private GoogleApiClient mGoogleApiClient;

    private FirebaseAuth mAuth;
    private FirebaseAuth.AuthStateListener mAuthListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_google_sign_in);

        // We can only get basic information using FirebaseAuth
        mAuth = FirebaseAuth.getInstance();
        mAuthListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user != null) {
                    // User is signed in to Firebase, but we can only get 
                    // basic info like name, email, and profile photo url
                    String name = user.getDisplayName();
                    String email = user.getEmail();
                    Uri photoUrl = user.getPhotoUrl();

                    // Even a user's provider-specific profile information
                    // only reveals basic information
                    for (UserInfo profile : user.getProviderData()) {
                        // Id of the provider (ex: google.com)
                        String providerId = profile.getProviderId();
                        // UID specific to the provider
                        String profileUid = profile.getUid();
                        // Name, email address, and profile photo Url
                        String profileDisplayName = profile.getDisplayName();
                        String profileEmail = profile.getEmail();
                        Uri profilePhotoUrl = profile.getPhotoUrl();
                    }
                } else {
                    // User is signed out of Firebase
                }
            }
        };

        // Google sign-in button listener
        findViewById(R.id.google_sign_in_button).setOnClickListener(this);

        // Configure GoogleSignInOptions
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.server_client_id))
                .requestServerAuthCode(getString(R.string.server_client_id))
                .requestEmail()
                .requestScopes(new Scope(PeopleScopes.USERINFO_PROFILE))
                .build();

        // Build a GoogleApiClient with access to the Google Sign-In API and the
        // options specified by gso.
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this, this)
                .addOnConnectionFailedListener(this)
                .addConnectionCallbacks(this)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.google_sign_in_button:
                signIn();
                break;
        }
    }

    private void signIn() {
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, RC_SIGN_IN);
    }

    @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) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (result.isSuccess()) {
                // Signed in successfully
                GoogleSignInAccount acct = result.getSignInAccount();

                // execute AsyncTask to get gender from Google People API
                new GetGendersTask().execute(acct);

                // Google Sign In was successful, authenticate with Firebase
                firebaseAuthWithGoogle(acct);
            }
        }
    }

    class GetGendersTask extends AsyncTask<GoogleSignInAccount, Void, List<Gender>> {
        @Override
        protected List<Gender> doInBackground(GoogleSignInAccount... googleSignInAccounts) {
            List<Gender> genderList = new ArrayList<>();
            try {
                HttpTransport httpTransport = new NetHttpTransport();
                JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance();

                //Redirect URL for web based applications.
                // Can be empty too.
                String redirectUrl = "urn:ietf:wg:oauth:2.0:oob";

                // Exchange auth code for access token
                GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(
                        httpTransport,
                        jsonFactory,
                        getApplicationContext().getString(R.string.server_client_id),
                        getApplicationContext().getString(R.string.server_client_secret),
                        googleSignInAccounts[0].getServerAuthCode(),
                        redirectUrl
                ).execute();

                GoogleCredential credential = new GoogleCredential.Builder()
                        .setClientSecrets(
                            getApplicationContext().getString(R.string.server_client_id), 
                            getApplicationContext().getString(R.string.server_client_secret)
                        )
                        .setTransport(httpTransport)
                        .setJsonFactory(jsonFactory)
                        .build();

                credential.setFromTokenResponse(tokenResponse);

                People peopleService = new People.Builder(httpTransport, jsonFactory, credential)
                        .setApplicationName("My Application Name")
                        .build();

                // Get the user's profile
                Person profile = peopleService.people().get("people/me").execute();
                genderList.addAll(profile.getGenders());
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            return genderList;
        }

        @Override
        protected void onPostExecute(List<Gender> genders) {
            super.onPostExecute(genders);
            // iterate through the list of Genders to
            // get the gender value (male, female, other)
            for (Gender gender : genders) {
                String genderValue = gender.getValue();
            }
        }
    }
}

You can find more information on Accessing Google APIs

kimbaudi
  • 13,655
  • 9
  • 62
  • 74
  • how can I get user's first name and last name . As **user.getGivenName()** and **user.getFamilyName()** are not working here . – xaif Dec 02 '19 at 17:38
3

For Facebook :

To get facebook accessToken from firebase is very simple. I was using firebase auth UI. After authentication with facebook you will get basic information from firebase user object like display name, email,provider details. But if you want more information like gender, birthday facebook Graph API is the solution. Once user authenticated with the facebook you can get access token like this.

AccessToken.getCurrentAccessToken() But sometimes it will give you NULL value instead of valid access token. Make sure that you have initialized facebook SDK before that.

public class MyApplication extends Application {
  @Override
  public void onCreate() {
     super.onCreate();
     FacebookSdk.sdkInitialize(this);
  }

} After initialization use graphAPI

if(AccessToken.getCurrentAccessToken()!=null) {

    System.out.println(AccessToken.getCurrentAccessToken().getToken());

    GraphRequest request = GraphRequest.newMeRequest(
            AccessToken.getCurrentAccessToken(),
            new GraphRequest.GraphJSONObjectCallback() {
                @Override
                public void onCompleted(JSONObject object, GraphResponse response) {
                    // Application code
                    try {
                        String email = object.getString("email");
                        String gender = object.getString("gender");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
    Bundle parameters = new Bundle();
    parameters.putString("fields", "id,name,email,gender,birthday");
    request.setParameters(parameters);
    request.executeAsync();

}
else
{
    System.out.println("Access Token NULL");
}

Happy Coding :)

Jitty Aandyan
  • 1,994
  • 1
  • 13
  • 12
1

No, you can't get these data directly. But you can use the id of the user and get these data from various providers. Please check before what are the data that are available in the public API for each of these providers for instance google just deprecated few methods from the peopleApi.

Anyways here is what i do for facebook

// Initialize Firebase Auth
FirebaseAuth mAuth = FirebaseAuth.getInstance();

// Create a listener
FirebaseAuth.AuthStateListener mAuthListener = firebaseAuth -> {
        FirebaseUser user = firebaseAuth.getCurrentUser();
        if (user != null) {
            // User is signed in
            Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
        } else {
            // User is signed out
            Log.d(TAG, "onAuthStateChanged:signed_out");
        }

        if (user != null) {
            Log.d(TAG, "User details : " + user.getDisplayName() + user.getEmail() + "\n" + user.getPhotoUrl() + "\n"
                    + user.getUid() + "\n" + user.getToken(true) + "\n" + user.getProviderId());

            String userId = user.getUid(); 
            String displayName = user.getDisplayName();
            String photoUrl = String.valueOf(user.getPhotoUrl());
            String email = user.getEmail();

            Intent homeIntent = new Intent(LoginActivity.this, HomeActivity.class);
            startActivity(homeIntent);
            finish();
        }
    };

//Initialize the fB callbackManager
mCallbackManager = CallbackManager.Factory.create();

And do the following inside the onClick of the FB login button

LoginManager.getInstance().registerCallback(mCallbackManager,
            new FacebookCallback<LoginResult>() {
                @Override
                public void onSuccess(LoginResult loginResult) {
                    Log.d(TAG, "facebook:onSuccess:" + loginResult);
                    handleFacebookAccessToken(loginResult.getAccessToken());
                }

                @Override
                public void onCancel() {
                    Log.d(TAG, "facebook:onCancel");
                }

                @Override
                public void onError(FacebookException error) {
                    Log.d(TAG, "facebook:onError", error);
                }
            });

LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile", "email"));
Gaurav Sarma
  • 2,248
  • 2
  • 24
  • 45
  • 1
    I can't see in your samples where you get the gender or the birth date? – TareK Khoury Sep 01 '16 at 09:52
  • Those are not provided my the firebase for that you will need to use the graph API by facebook and the uid that you get here for doing various queries to the graph API. https://developers.facebook.com/docs/graph-api – Gaurav Sarma Sep 01 '16 at 09:56
  • I see, so it cannot be done using the Firebase sdk. I need to use the Graph API or People API individually to get them – TareK Khoury Sep 01 '16 at 10:19
  • Yes firebase alone can't give you all that. It will just do enough to authenticate the user than using the user's id you need to get other data according to the permission methods of different providers – Gaurav Sarma Sep 01 '16 at 10:38
  • @TareKhoury Please accept the answer if it was in anyways helpful in answering your question. Regards – Gaurav Sarma Sep 01 '16 at 10:41
1

Instead of using Googles People API classes to access their REST service I find it much simpler to just access the service directly.

Also saves 1.5 MB of APK size.

  public static final String USER_BIRTHDAY_READ = "https://www.googleapis.com/auth/user.birthday.read";
  public static final String USER_PHONENUMBERS_READ = "https://www.googleapis.com/auth/user.phonenumbers.read";
  public static final String USERINFO_EMAIL = "https://www.googleapis.com/auth/userinfo.email";
  public static final String USERINFO_PROFILE = "https://www.googleapis.com/auth/userinfo.profile";

  public JSONObject getUserinfo(@NotNull Context context, @NotNull GoogleSignInAccount acct) {

    try {
      String token = GoogleAuthUtil.getToken(context, acct.getAccount(), "oauth2: " +USERINFO_PROFILE+" "+USER_PHONENUMBERS_READ+" "+USERINFO_EMAIL+" "+USER_BIRTHDAY_READ);

      URL url = new URL("https://people.googleapis.com/v1/people/me?"
              +"personFields=genders,birthdays,phoneNumbers,emailAddresses"
              +"&access_token=" + token);
      HttpURLConnection con = (HttpURLConnection) url.openConnection();
      int sc = con.getResponseCode();
      if (sc == 200) {
        InputStream is = con.getInputStream();
        JSONObject profile = new JSONObject(readStream(is));
        Log.d(TAG, "Got:" + profile.toString(2));
        Log.d(TAG, "genders: "+profile.opt("genders"));
        Log.d(TAG, "birthdays: "+profile.opt("birthdays"));
        Log.d(TAG, "phoneNumbers: "+profile.opt("phoneNumbers"));
        return profile;
      } else if (sc == 401) {
        GoogleAuthUtil.clearToken(context, token);
        Log.d("Server auth fejl, prøv igen\n" + readStream(con.getErrorStream()));
      } else {
        Log.d("Serverfejl: " + sc);
      }
  } catch (UserRecoverableAuthException recoverableException) {
    startActivityForResult(recoverableException.getIntent(), 1234);
  } catch (Exception e) {
    e.printStackTrace();
  }

  public static String readStream(InputStream is) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] data = new byte[2048];
    int len = 0;
    while ((len = is.read(data, 0, data.length)) >= 0) {
      bos.write(data, 0, len);
    }
    is.close();
    return new String(bos.toByteArray(), "UTF-8");
  }

Output is easily parsable as JSON:

genders: [{"metadata":{"primary":true,"source":{"type":"PROFILE","id":"101628018970026223117"}},"value":"male","formattedValue":"Male"}]
birthdays:  [{"metadata":{"primary":true,"source":{"type":"PROFILE","id":"101628018970026223117"}},"date":{"year":1985,"month":3,"day":5}},{"metadata":{"source":{"type":"ACCOUNT","id":"101628018970026223117"}},"date":{"year":1985,"month":3,"day":5}}]
Jacob Nordfalk
  • 3,533
  • 1
  • 21
  • 21