9

My android app currently uses the GoogleAuthUtil to signin users and fetch an access_token which is passed to the backend (code snippets below which show creating the GoogleApiClient and using GoogleAuthUtil to get the token).

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

String accessToken = GoogleAuthUtil.getToken(GoogleLoginActivity.this,
                            Plus.AccountApi.getAccountName(mGoogleApiClient),
                            "oauth2:profile email");

which I then sent to the backend

I am now trying to move to the new Google SignIn - https://developers.google.com/identity/sign-in/android/sign-in

and so changed the GoogleApiClient creation like,

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestEmail()
        .requestIdToken("<web client id>")
        .build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this, this)
        .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
        .build();

and then to do the login use,

startActivityForResult(Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient), RC_GET_TOKEN);

and on activity result use (similar to the example in the link above),

OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
    // If the user's cached credentials are valid, the OptionalPendingResult will be "done"
    // and the GoogleSignInResult will be available instantly.
    Log.d(TAG, "Got cached sign-in");
    handleSignInResult(opr.get());
} else {
    // If the user has not previously signed in on this device or the sign-in has expired,
    // this asynchronous branch will attempt to sign in the user silently.  Cross-device
    // single sign-on will occur in this branch.
    showProgress();
    opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
        @Override
        public void onResult(GoogleSignInResult googleSignInResult) {
            hideProgress();
            handleSignInResult(googleSignInResult);
        }
    });
}

but now it seems that in handleSingInResult(GoogleSignInResult result) I can only get an id token back with result.getSignInAccount().getIdToken();

Does anyone know if it is possible to get an access token from this (like previously) and if so how? Any help appreciated.

Bootstrapper
  • 1,089
  • 3
  • 14
  • 33
  • I'm having the same issue here, have you managed to work your way around this issue? – Thalis Vilela Dec 03 '15 at 17:30
  • Not really. Had to implement id token handling in the backend before I could start using this. – Bootstrapper Dec 14 '15 at 15:53
  • I ended up using Android's account picker to get the account name, and the GoogleAuthUtil.getToken(Context, accoutName, scope) to retrieve the token itself, it worked like a charm and a lot simpler then the first approuch. – Thalis Vilela Dec 15 '15 at 16:56
  • I considered doing that myself initially but then realized that there was lot less code and error paths in the app to deal with (related to using the GoogleApiClient `connect()` etc.) if I just added idToken parsing to the backend. – Bootstrapper Dec 17 '15 at 11:13

2 Answers2

6

After signing in you'll be able to get the token:

final String token = GoogleAuthUtil.getToken(mAppContext, mAccountName, AUTH_TOKEN_TYPE);

dont forget to do it an Asynctask. for more detail have a look at here

EDIT:

Note that, despite the method name:

GoogleAuthUtil.getToken()

it does not give you an OAuth Token, it rather returns a "short-lived authorization code" according to the documentation.

What I should do after getting the Authorization Code by calling the GoogleAuthUtil.getToken() ?

You should transmit the Authorization Code to your backend server over HTTPS. Only from your server you should attempt to receive Access and/or Refresh token, not in your app.

abedfar
  • 1,989
  • 24
  • 21
2

So i was having the same problem. they have changed it now so the token comes through in

GoogleSignInAccount acct = result.getSignInAccount();
Log.d(TAG, "handleSignInResult2: "+acct.getIdToken());

To get access too this token you have too ask for it in

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail().requestProfile().requestId().requestIdToken(getString(R.string.server_client_ID))
                    .build();

The R.string.server_client_ID is the client ID from the project that you make in your Google developer Console.

I hope this helps you.

here is also the documentation i followed. https://developers.google.com/identity/sign-in/android/backend-auth

Hashoo
  • 47
  • 7
pjapple15
  • 299
  • 4
  • 10
  • 6
    as I mentioned in my question, the token received this way is an `id_token` and not an `access_token`. So for now it looks like we still need to fetch the `access_token` the same way as before with the `GoogleAuthUtil.getToken()` in an AsyncTask (I was kind of hoping there would be another way but anyway...) – Bootstrapper Nov 27 '15 at 22:34
  • That's correct. id_token need to be exchanged for access_token. – Uma sankar pradhan Jul 05 '16 at 06:51
  • Please correct me, but it seems that id_token can't be exchanged to access_token. id_token contains user info encoded inside the token itself. If you want to get access_token, you need to request for server Auth code (`getServerAuthCode`). This is unfortunate, because when you request for server Auth code, Google notify user that the app request "Work Offline". – Mike Keskinov Feb 12 '19 at 23:59