Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regeneration of "one time authorization code" for Google+ on Android

I am working with authenticating via Google+ according to the following: https://developers.google.com/+/mobile/android/sign-in

Most of this process seems fine. The problem I'm having is that we need to get a "one-time authorization code" so that our backend servers can perform certain requests on behalf of the user, with their permission. This is covered in the section "Enable server-side api access for your app". However, for a number of reasons, our servers can cause the login to fail, even if the authorization code is valid (e.g. the user doesn't have an account corresponding to the google+ account on our servers yet, in which case they can make one).

If this happens, we might need them to login again at a later time. What I'm finding, though, is that when I perform the second login with google+, it gives me the same authorization code, even if it's already been used by our servers. I've tried disconnecting and reconnecting to the google client api, and calling GoogleApiClient.clearDefaultAccountAndReconnect(), but no matter what I do, I seem to end up with the same authorization code. This, of course, is rejected by the server when it tries to use it, since it's already been used.

I'm wondering what I'm doing wrong here. I have the following method, which is called during the initial authentication process, and then again if a response status of 500 is detected from our server (indicating the previous call failed, presumably because the code has already been used):

  private void dispatchGooglePlusAuthCodeAcquisition() {
    AsyncTask<Void, Void, String> authAcquisition = new AsyncTask<Void, Void, String>() {
      @Override
      protected String doInBackground(Void... params) {
        Bundle authPreferences = new Bundle();
        mUserPermissionNeededForAuthCode = false;
        authPreferences.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
                                "");
        String scopesString = Scopes.PROFILE;
        WhenIWorkApplication app = (WhenIWorkApplication)WhenIWorkApplication.getInstance();
        String serverClientID = app.getGoogleOAuthClientIDForPersonalServer();
        String scope = "oauth2:server:client_id:" + serverClientID + ":api_scope:" + scopesString;
        String code = null;
        authPreferences.putBoolean(GoogleAuthUtil.KEY_SUPPRESS_PROGRESS_SCREEN, true);

        try {
          code = GoogleAuthUtil.getToken(
            mActivity,
            Plus.AccountApi.getAccountName(mGoogleApiClient),
            scope,
            authPreferences
          );
        } 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.
          Log.d(LOGTAG, "Encountered an IOException while trying to login to Google+."
                                   + " We'll need to try again at a later time.");
        } catch (UserRecoverableAuthException e) {
          mUserPermissionNeededForAuthCode = true;
          // Requesting an authorization code will always throw
          // UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
          // because the user must consent to offline access to their data.  After
          // consent is granted control is returned to your activity in onActivityResult
          // and the second call to GoogleAuthUtil.getToken will succeed.
          if (!mGooglePlusPermissionActivityStarted) {
            mGooglePlusPermissionActivityStarted = true;
            mActivity.startActivityForResult(e.getIntent(), RESULT_CODE_AUTH_CODE);
          }
        } catch (GoogleAuthException authEx) {
          // Failure. The call is not expected to ever succeed so it should not be
          // retried.
          Log.e(LOGTAG, "Unable to authenticate to Google+. Call will likely never"
                                   + " succeed, so bailing.", authEx);
        }

        return code;
      }

      @Override
      protected void onPostExecute(String aResult) {
        if (aResult != null) {
          // We retrieved an authorization code successfully.
          if (mAPIAccessListener != null) {
            mAPIAccessListener.onAuthorizationCodeGranted(aResult);
          }
        } else if (!mUserPermissionNeededForAuthCode) {
          // If this is the case, then we didn't get authorization from the user, or something
          // else happened.
          if (mAPIAccessListener != null) {
            mAPIAccessListener.onAuthorizationFailed();
          }

          Log.d(LOGTAG, "Unable to login because authorization code retrieved was null");
        }
      }
    };

    authAcquisition.execute();
like image 629
jwir3 Avatar asked Oct 20 '22 13:10

jwir3


1 Answers

So, the answer to this was a lot simpler than I imagined. Apparently, there is aclearToken() method on the GoogleAuthUtil class:

http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html#clearToken%28android.content.Context,%20java.lang.String%29

public static void clearToken (Context context, String token)

Clear the specified token in local cache with respect to the Context. Note that the context must be the same as that used to initialize the token in a previous call to getToken(Context, String, String) or getToken(Context, String, String, Bundle).

Parameters

context Context of the token.
token The token to clear.

Throws

GooglePlayServicesAvailabilityException
GoogleAuthException
IOException

Calling this method before attempting to re-authenticate causes Google to generate a new one-time authorization token.

like image 175
jwir3 Avatar answered Oct 24 '22 07:10

jwir3