5

I am trying to get the user's information, including gender and age, from its Google Plus account. Since these fields may be private, I thought that requesting them explicitly would solve the problem. However, although the sign in dialog states explicitly that the app requests to View your complete date of birth, I fail to get the birthday.

These are my scopes (tried many variations):

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        //.requestScopes(new Scope(Scopes.PROFILE))
        //.requestScopes(new Scope(Scopes.PLUS_LOGIN))
        .requestScopes(new Scope("https://www.googleapis.com/auth/user.birthday.read"),
                new Scope("https://www.googleapis.com/auth/userinfo.profile"))
        //.requestProfile()
        .requestEmail()
        .build();

mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this, this)
        .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
        .addApi(Plus.API)
        .addScope(new Scope(Scopes.PROFILE))
        .build();

When using the deprecated getCurrentPerson in onActivityResult, I get null value:

if (requestCode == RC_SIGN_IN) {
    GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);

    if (mGoogleApiClient.hasConnectedApi(Plus.API)) {
        Person person  = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
        if (person != null) {
            Log.i(TAG, person.getDisplayName());    //returns full name successfully
            Log.i(TAG, person.getGender());         //0
            Log.i(TAG, person.getBirthday());       //null
        }
    }
}

I also tried to get it from the account (GoogleSignInAccount account = result.getSignInAccount()) but as far as I've searched, this variable doesn't own the requested data at all.

Am I missing something? Or maybe it's impossible to get private data although explicit request?

Thanks.

BTW, I haven't tried yet a scenario with a private gender.

BNK
  • 23,994
  • 8
  • 77
  • 87
Neria Nachum
  • 1,519
  • 1
  • 20
  • 37

2 Answers2

5

I think this Google People API documentation will be helpful for your issue.

Please pay attention to:

If the request requires authorization (such as a request for an individual's private data), then the application must provide an OAuth 2.0 token with the request. The application may also provide the API key, but it doesn't have to.

and

Requests to the People API for non-public user data must be authorized by an authenticated user.

...

  1. If the user approves, then Google gives your application a short-lived access token.
  2. Your application requests user data, attaching the access token to the request.
  3. If Google determines that your request and the token are valid, it returns the requested data.

If your app has not got an access token, you can read Using OAuth 2.0 to Access Google APIs or try my answer at the following question:

How to get access token after user is signed in from Gmail in Android?


UPDATE: Supposing that your app can get the access token by using the sample code in my answer above, then inside onResponse, add more snippets as below:

...
@Override
public void onResponse(Response response) throws IOException {
    try {
        JSONObject jsonObject = new JSONObject(response.body().string());
        final String message = jsonObject.toString(5);
        Log.i("onResponse", message);

        // FROM HERE...
        String accessToken = jsonObject.optString("access_token");

        OkHttpClient client2 = new OkHttpClient();
        final Request request2 = new Request.Builder()
                .url("https://people.googleapis.com/v1/people/me")
                .addHeader("Authorization", "Bearer " + accessToken)
                .build();

        client2.newCall(request2).enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                Log.e("onFailure", e.toString());
            }

            @Override
            public void onResponse(Response response) throws IOException {
                try {
                    JSONObject jsonObject = new JSONObject(response.body().string());
                    final String message = jsonObject.toString(5);
                    Log.i("onResponse", message);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    } catch (JSONException e) {
        e.printStackTrace();
    }
}
...

Logcat info (I truncated since it's long)

I/onResponse: {
                   "photos": [
                        {
                             "url": "https:...photo.jpg",
                             "metadata": {
                                  "source": {
                                       "id": "1....774",
                                       "type": "PROFILE"
                                  },
                                  "primary": true
                             }
                        }
                   ],
                   ...                                                                               
                   "birthdays": [
                        {
                             "date": {
                                  "month": 2,
                                  "year": 1980,
                                  "day": 2
                             },
                             "metadata": {
                                  "source": {
                                       "id": "1....774",
                                       "type": "PROFILE"
                                  },
                                  "primary": true
                             }
                        }
                   ],
                   ....
              }

GoogleSignInOptions and GoogleApiClient:

String serverClientId = getString(R.string.server_client_id);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestScopes(new Scope("https://www.googleapis.com/auth/user.birthday.read"))
        .requestServerAuthCode(serverClientId)
        .build();

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
        .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
        .build();

Please note that the OkHttp version I use here is v2.6.0, if your app uses the newest (3.3.1), then the syntax/classes will be different. Of course, you can also use the others such as Volley, Retrofit...


Moreover, this Google's People API - Method people.get provides Try It as screenshot below

enter image description here

Other useful links:

Google Developers Blog - Announcing the People API

Google APIs related to Google People API

Authorizing with Google for REST APIs (another way to get access token)

Community
  • 1
  • 1
BNK
  • 23,994
  • 8
  • 77
  • 87
  • 1
    Please remember the question is about the Google plus api he didn't ask about the people api. This may or may not be helpful but it doesn't anwser his question – Linda Lawton - DaImTo Jun 23 '16 at 04:59
  • @DalmTo sorry if I misunderstand the OP's question, looks like that he did not mention the API. Moreover, his code also uses PeopleApi insile Plus, which is now deprecated :) – BNK Jun 23 '16 at 05:25
  • Either way deleting my answer to avoid any confusion. – Linda Lawton - DaImTo Jun 23 '16 at 06:44
  • I got myself a bit confused with these somehow related API's. Anyway, your links and snippets were useful, I'm still digging into it and will post a complete answer once I nail it. Thanks! – Neria Nachum Jun 23 '16 at 14:12
  • About these Google's APIs, I think you can read https://developers.googleblog.com/2016/02/announcing-people-api.html and https://developers.google.com/people/related-apis – BNK Jun 23 '16 at 14:29
  • I managed to receive the JSON with the user info successfully but no 'birthdays' in it, only basic profile, genders, locales and ageRange. Do you think that serverClientId may be relevant? I'm pretty sure it's not, but anyway at the moment I'm not calling `requestServerAuthCode`. Any idea will be appreciated. Thanks! – Neria Nachum Jun 26 '16 at 07:28
  • Have you provided an OAuth 2.0 token (access token) with the request? If not, only public data can be received. Please note that auth code is used to get the access token, or you can use another way to get the access token as I mentioned at the end of my answer – BNK Jun 26 '16 at 13:17
  • Yes, I provided the auth token, though I received it in a different way than the one you mentioned. I created a class that implements `AccountManagerCallback` to handle the call to `AccountManager.getAuthToken` (the token is then stored in `AccountManager.KEY_AUTHTOKEN`). I receive the access token successfully. Is there a chance that I'm getting a 'wrong' access token? – Neria Nachum Jun 27 '16 at 07:25
  • I have not tried with `AccountManager.getAuthToken`, however, perhaps [this link](http://blog.tomtasche.at/2013/05/google-oauth-on-android-using.html) will be helpful for you, and try with the SCOPE `oauth2:https://www.googleapis.com/auth/userinfo.profile` – BNK Jun 27 '16 at 08:30
  • Some other good links for you http://stackoverflow.com/questions/14365219/in-a-nutshell-whats-the-difference-from-using-oauth2-request-getauthtoken-and-g and http://stackoverflow.com/questions/22142641/access-to-google-api-googleaccountcredential-usingoauth2-vs-googleauthutil-get :) – BNK Jun 27 '16 at 08:40
  • Hi! Have you got the birthday value yet? – BNK Jul 01 '16 at 14:13
  • I was deflected from this mission before I managed to solve it... Hopefully I'll be back on it soon, but unfortunately I cannot guarantee. – Neria Nachum Jul 03 '16 at 07:29
0

Try this initialization

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).addApi(Plus.API)
                .addScope(Plus.SCOPE_PLUS_LOGIN).build();

else requested user needs to have public visibility of the birthday.

Nisarg
  • 1,358
  • 14
  • 30