6
votes

I have a client and server app that needs to access a users g+ profile after on the SERVER side once they've validated on the client (android)

I'm gettin an ID token on the client side by this

@Background
void getAccessToken() {


    String scopes = "audience:server:client_id:xxxxxxxxxxxxx.apps.googleusercontent.com";

    Log.d(TAG,scopes);

    try {

        accessToken = GoogleAuthUtil.getToken(this,mPlusClient.getAccountName(),scopes);

        Log.d(TAG,accessToken);

        getPlusFriends();

    }
    catch (IOException transientEx) {
        Log.e(TAG, transientEx.getMessage());
        return;
    }
    catch (UserRecoverableAuthException e) {
        Log.e(TAG, e.getMessage());
        accessToken = null;
    }
    catch (GoogleAuthException authEx) {
        Log.e(TAG, authEx.getMessage());

        return;
    }
    catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Which will give me a long ID token as described in this blog http://www.tbray.org/ongoing/When/201x/2013/04/04/ID-Tokens

I think I'm supposed to send that token to my server where I need to do something to turn it into an access_token. I can verify that the id token? is good by sending a curl request to

https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=

which gives back a json string like this

{
"issuer": "accounts.google.com",
"issued_to": "xxxxxxxxxxxxxx.apps.googleusercontent.com",
"audience": "xxxxxxxxxxxxxx.apps.googleusercontent.com",
"user_id": "123456",
"expires_in": 3362,
"issued_at": 1382577073,
"email": "myemail@something",
"verified_email": true
}

php server

\Config::load('google_api', 'google');

 $key = Config::get('google.client_id');
 $secret = Config::get('google.client_secret');
 $scopes = Config::get('google.scopes');

 $client = new Google_Client();

 $client->setClientId($key);
 $client->setClientSecret($secret);
 $client->setScopes($scopes);
 $client->setState('offline');
 $client->authenticate($token);

where the issued_to is my client id for the Android app in the Google APIs console and the audience is the client is of my web app, seems right so far I think.

So now I'm using the php client and not really sure what to do from there. I tried to validate the api client using the id token but I just get the error 400 - Error fetching OAuth2 access token, message: 'invalid_grant'

I'm not sure if I'm supposed to try to authenticate the PHP Google+ client using that ID token or some how exchange it for an access token

2

2 Answers

5
votes

Did you read the Server-side access for your app documentation?

What you need is a one-time authorization code that you pass to your server and the server exchanges that authorization code for its own access and refresh tokens. The ID tokens are useful for verifying that the app and user are who they say they are, but not for getting your server access to data.

Your code is close, but is missing some key parts to make this work, such as specifying the app activity types that your app initially requested in the PlusClient configuration, and your scopes string needs a change.

Taken from the docs:

Bundle appActivities = new Bundle();
appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
          "<app-activity1> <app-activity2>");
String scopes = "oauth2:server:client_id:<server client-id>:api_scope:<scope1> <scope2>";
String code = null;
try {
  code = GoogleAuthUtil.getToken(
    this,                             // Context context
    mPlusClient.getAccountName(),     // String accountName
    scopes,                           // String scope
    appActivities                     // Bundle bundle
  );

} catch (IOException transientEx) {
  // network or server error, the call is expected to succeed if you try again later.
  // Don't attempt to call again immediately - the request is likely to
  // fail, you'll hit quotas or back-off.
  ...
  return;
} catch (UserRecoverableAuthException e) {
  // Recover
  code = null;
} catch (GoogleAuthException authEx) {
  // Failure. The call is not expected to ever succeed so it should not be
  // retried.
  ...
  return;
} catch (Exception e) {
  throw new RuntimeException(e);
}

The code that you get back, you pass to your server. See line 98 in the PHP quick-start for how to perform the code exchange (and other steps like verifying the ID) using the PHP client library. You'll also need to configure your PHP client for offline access. The basics are:

$client = new apiClient();
$client->setClientId('From APIs console');
$client->setClientSecret('From APIs console');
$client->setScopes('exact same list of scopes as Android app, space separated');
$client->setRedirectUri('postmessage');  // Used in hybrid flows
$client->setState('offline');
// Exchange authorization code for access and refresh tokens
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
0
votes

If you care about ID Tokens, the place to start reading is probably here: https://developers.google.com/accounts/docs/OAuth2Login

But if what you’re trying to do is access someone’s G+ profile and you’re in PHP-land, check out the PHP quick-start at https://developers.google.com/+/quickstart/php - it’s probably easier than you think.