1

I am using Google Drive cross client identity so that when user gives Drive access permission to my Android App, my web server also gains access to user Google Drive.

For this firstly I have to get an Authorization code. For this I am using following code:

private String getAccessToken(Context mContext) {
      String SERVER_CLIENT_ID = "1009999994.apps.googleusrcontent.com";
      String scopes = "oauth2:server:client_id:"+SERVER_CLIENT_ID+":api_scope:"+DriveScopes.DRIVE;
      String accessToken = null;

      try {
        accessToken = GoogleAuthUtil.getToken(mContext, accountName, scopes); 
        Log.d("token is:", "token:"+accessToken);
    } catch (UserRecoverableAuthException e) {

        e.printStackTrace();
    } catch (IOException e) {

        e.printStackTrace();
    } catch (GoogleAuthException e) {

        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }

      return accessToken;
  }

Here is exception I got in Logcat:

   07-20 12:12:10.210: W/GLSActivity(29164): [qq] Status from wire: INVALID_SCOPE status: INVALID_SCOPE
    07-20 12:12:12.453: W/System.err(29037): com.google.android.gms.auth.GoogleAuthException: INVALID_SCOPE
    07-20 12:12:12.492: W/System.err(29037):    at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
    07-20 12:12:12.492: W/System.err(29037):    at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
    07-20 12:12:12.500: W/System.err(29037):    at com.example.googledriveaccess1.MainActivity.getAccessToken(MainActivity.java:161)
    07-20 12:12:12.500: W/System.err(29037):    at com.example.googledriveaccess1.MainActivity.access$0(MainActivity.java:155)

Here I am using same project for both Android and Server side access. I am also passing Client-ID for web.

Earlier I was using not using Cross-Client Identity and my app getting access token correctly.

previously my scope was

String scope = "oauth2:"+DriveScopes.DRIVE;

Waiting for your reply

Edit:2

Here I am uploading my full code. In this code INVALID_SCOPE problem resolved after I use PLUS.LOGIN scope as well with DriveScope.Drive.

package com.example.googleaccess;

import java.io.IOException;

import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;

import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.GooglePlayServicesAvailabilityException;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.plus.PlusClient;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.services.drive.DriveScopes;


public class MainActivity extends Activity {

    private String accountName = null;
    private GoogleAccountCredential credential;
    private int REQUEST_ACCOUNT_PICKER = 2;
    private int REQUEST_AUTHORIZATION = 11;

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String CLIENT_ID = "60000000007.apps.googleusercontent.com";
        String scope = "server:client_id:"+CLIENT_ID+":api_scope:"+DriveScopes.DRIVE+" "+"https://www.googleapis.com/auth/plus.login";
        credential = GoogleAccountCredential.usingOAuth2(MainActivity.this, scope);
        startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
        GooglePlayServicesUtil.isGooglePlayServicesAvailable(MainActivity.this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return false;
    }

    class Async extends AsyncTask<Void, Void, Void> {

        Context credential = null;

        public Async(Context credential) {
            this.credential = credential;
        }

        @Override
        protected Void doInBackground(Void... params) {
            getAccessToken(credential);
            return null;
        }

    }

    public void getAccessToken(Context mContext) {

        try {

            String token = credential.getToken();
            Log.d("Token", "token:"+token);
        } catch (GooglePlayServicesAvailabilityException playEx) {
            playEx.getMessage();
            playEx.printStackTrace();

          }catch (UserRecoverableAuthException e) {
            e.printStackTrace();
            Log.d("Token", "token:"+e.getCause());

            startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("Token", "token:"+e.getMessage());
        } catch (GoogleAuthException e) {
            e.printStackTrace();
            Log.d("Token", "token:"+e.getMessage());
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == REQUEST_ACCOUNT_PICKER) {
            if (resultCode == RESULT_OK && data != null && data.getExtras() != null) {
            accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);

                if (accountName != null) {
                  credential.setSelectedAccountName(accountName);

                  new Async(getApplicationContext()).execute();
                }
              }
        }

        if(requestCode == REQUEST_AUTHORIZATION) {
            if (resultCode == Activity.RESULT_OK) {
                data.getExtras();
                new Async(getApplicationContext()).execute();
              } else {
                  startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
              }
        }
    }


}

Now I always got Need_Permission exception, I always gives permission from device but it's not working. Again and again NEED_EXCEPTION error comes. You can also try my code by inputting your project CLIENT_ID. Please help me I am really stuck at this point.

May be there be any more permission I have to give but I don't now which permission.

Sorry for my bad english.

Sagar Trehan
  • 2,401
  • 2
  • 24
  • 32
  • can somebody help me with this problem? – Sagar Trehan Jul 20 '13 at 07:17
  • please help me and tell me if any more information is needed for this – Sagar Trehan Jul 20 '13 at 09:03
  • Please reply my question I am asking it from long time. – Sagar Trehan Jul 23 '13 at 11:09
  • Should I asked my problem in different question? – Sagar Trehan Jul 23 '13 at 11:52
  • This question has also been asked here: http://stackoverflow.com/questions/17713435/android-google-integration-repeated-userrecoverableauthexception/17725668?noredirect=1#comment25851210_17725668 – Lee Jul 23 '13 at 15:15
  • Since when did the GoogleAuthUtil.getToken() method start throwing a GoogleAuthException with message "BadUsername" for an email that is not registered on a device, instead of the previous exception IllegalArgumentException with message "Non existing account 'email_address'" ? http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context , java.lang.String, java.lang.String) – Etienne Lawlor Nov 06 '13 at 02:35

2 Answers2

5

Use GoogleAuthUtil.getToken to retrieve the exchange code.

final private String CLIENT_ID = "abc123.apps.googleusercontent.com";
final private List<String> SCOPES = Arrays.asList(new String[]{
    "https://www.googleapis.com/auth/plus.login",
    "https://www.googleapis.com/auth/drive"
});

String scope = String.format("oauth2:server:client_id:%s:api_scope:%s", CLIENT_ID, TextUtils.join(" ", SCOPES));
String exchangeCode = GoogleAuthUtil.getToken(context, accountName, scope);

A working sample is on https://github.com/googledrive/crossclientoauth2-android and it's more in detail explained on https://developers.google.com/drive/auth/android#cross-client_identity

Burcu Dogan
  • 9,153
  • 4
  • 34
  • 34
  • Thanks Burcu for replying, I tried to keep the scope = "audience:server:" + SERVER_CLIENT_ID; but getting same INVALID_SCOPE Exception. Also I have to give DriveScopes.DRIVE in scope so that user gives permission to access it on App and we could use this permission on server side using Cross Client Identity. – Sagar Trehan Jul 20 '13 at 10:21
  • It should be fine to request Drive scope as well, but for now the docs note that "This policy in being rolled out gradually. For the moment, when Access Tokens, are involved, it only applies when the requested scopes include https://www.googleapis.com/auth/plus.login" so you should be sure to include the plus.login scope as well. – aeijdenberg Jul 20 '13 at 22:08
  • Hey Aeijdenberg thanks for guide me, when I include PLUS_LOGIN scope the Exception INVALID_SCOPE eliminated. But now I am getting NEED_PERMISSIOn Exceptionin code. Please check my updated code. – Sagar Trehan Jul 22 '13 at 06:27
  • Please asked me if any other details needed – Sagar Trehan Jul 22 '13 at 08:10
  • Please help me. If you want then I could paste logcat output as well – Sagar Trehan Jul 22 '13 at 11:03
  • I got weird problem in it. Firstly I was testing this code on my samsung 2.3.6 device. But now I had tested it on emulator 4.2 with google Api Level 17 and it's working now. Can somebody help me with this problem. – Sagar Trehan Jul 22 '13 at 12:43
  • Hey somebody tell me why I am facing this problem. It should work on other devices as well. – Sagar Trehan Jul 22 '13 at 13:37
  • I am also checking GooglePlayServicesUtil.isGooglePlayServicesAvailable(MainActivity.this) and it's return success as well – Sagar Trehan Jul 22 '13 at 15:10
  • Take a look at https://developers.google.com/drive/auth/android#cross-client_identity, there is working sample. – Burcu Dogan Jul 23 '13 at 17:30
  • Thanks Burcu Dogan for uploading code on GitHub. I am testing it on my device and will respond to you soon. – Sagar Trehan Jul 24 '13 at 04:43
  • No Burcu I have tested with your code as well. Authentication code fetching works on emulator 4.2.2 Google API Level 17 but not on my device supporting Android 2.3.6. While Exchange code access token fetch correctly. Here [link](http://chat.stackoverflow.com/rooms/33772/discussion-between-lee-and-arkaaito) **Evelio** and **Arkaaito** working on same problem, please see if you can contribute something here. – Sagar Trehan Jul 24 '13 at 05:05
  • You can also test this code on other Android devices as well to understand problem clearly. – Sagar Trehan Jul 24 '13 at 08:01
  • What's the version of the Play Services you have on your device? – Burcu Dogan Jul 25 '13 at 15:14
  • Hey @Burcu Dogan, this used to work for me, but only a few days ago it stopped working and now it throws this error `com.google.android.gms.auth.GoogleAuthException: Unknown.` Any idea why? Is there something wrong with my scopes? https://gist.github.com/lawloretienne/7351151 – Etienne Lawlor Nov 07 '13 at 16:33
  • can you please help me on this bug http://stackoverflow.com/questions/21445265/google-coordinate-authentification – haythem souissi Jan 30 '14 at 00:00
  • what **accountName** means ? – Prashant Date Sep 13 '16 at 06:44
0

code in example:

startActivityForResult(userRecoverableException.getIntent(), CalendarSampleActivity.REQUEST_AUTHORIZATION);

full code:

} catch (final GooglePlayServicesAvailabilityIOException availabilityException) {
      activity.showGooglePlayServicesAvailabilityErrorDialog(
          availabilityException.getConnectionStatusCode());
    } catch (UserRecoverableAuthIOException userRecoverableException) {
      activity.startActivityForResult(
          userRecoverableException.getIntent(), CalendarSampleActivity.REQUEST_AUTHORIZATION);
    } catch (IOException e) {
      Utils.logAndShow(activity, CalendarSampleActivity.TAG, e);
    }
    return false;
Long Rainbow
  • 328
  • 3
  • 10