ArtOfWarfare
ArtOfWarfare

Reputation: 21486

Google Drive Returning Error 400 or 403 to my Android App?

Here's my code for requesting the auth token...

AccountManager am = AccountManager.get(this);
Bundle options = new Bundle();
am.getAuthToken(
    (am.getAccounts())[0], // My test device only has one account. I'll add a picker before releasing this app.
    "oauth2:" + DriveScopes.DRIVE,
    options,
    true, // I've tried both true and false... doesn't seem to change anything?
    new OnTokenAcquired(),
    null); // I used to have a handler, but it absolutely never got called.

Here's the code that handles the token:

private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
    @Override
    public void run(AccountManagerFuture<Bundle> result) {
        String token = result.getResult().getString(AccountManager.KEY_AUTHTOKEN);

        HttpTransport httpTransport = new NetHttpTransport();
        JacksonFactory jsonFactory = new JacksonFactory();

        Drive.Builder b = new Drive.Builder(httpTransport, jsonFactory, null);
        b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
            @Override
            public void initialize(JsonHttpRequest request) throws IOException {
                DriveRequest driveRequest = (DriveRequest) request;
                driveRequest.setPrettyPrint(true);
                driveRequest.setKey("xxxxxxxxxxxx.apps.googleusercontent.com"); // I replaced the number with x's. I'll explain where I got the number from below.
                driveRequest.setOauthToken(token);
            }
        });

        final Drive drive = b.build();

        final com.google.api.services.drive.model.File body = new com.google.api.services.drive.model.File();
        body.setTitle("My document");
        body.setDescription("A test document");
        body.setMimeType("text/plain");

        java.io.File fileContent = new java.io.File("document.txt");
        final FileContent mediaContent = new FileContent("text/plain", fileContent);

        new Thread(new Runnable() {
            public void run() {
                com.google.api.services.drive.model.File file;
                try {
                    file = drive.files().insert(body, mediaContent).execute();
                    Log.i("Hi", "File ID: " + file.getId());
                } catch (IOException e) {
                    Log.i("Hi", "The upload/insert was caught, which suggests it wasn't successful...");
                    e.printStackTrace();
                    AccountManager am = AccountManager.get(activity);
                    am.invalidateAuthToken(am.getAccounts()[0].type, null);
                    Bundle options = new Bundle();
                    am.getAuthToken(
                        (am.getAccounts())[0],
                        "oauth2:" + DriveScopes.DRIVE,
                        options,
                        true,
                        new OnTokenAcquired(),
                        null);
                    }
                }
            }).start();
        Intent launch = (Intent)result.getResult().get(AccountManager.KEY_INTENT);
        if (launch != null) {
            Log.i("Hi", "Something came back as a KEY_INTENT");
            startActivityForResult(launch, 3025);
            return;
        } else {
            Log.i("Hi", "I checked, but there was nothing for KEY_INTENT.");
        }
    }
}

I have implemented onActivityResult and have it set up to log the requestCode and resultCode if it's ever invoked, but it never is. Were it to ever be invoked, it just fires off another token request if the requestCode is 3025 and the resultCode is RESULT_OK.

Here's how I got my clientID:

As it is, here's what I get from the log:

I checked, but there was nothing for KEY_INTENT // My log message.
The upload/insert was caught, which suggests it didn't work... // Another one of my log messages.
com.google.api.client.http.HttpResponseException: 400 Bad Request
{
 "error": {
  "errors": [
   {
    "domain": "usageLimits",
    "reason": "keyInvalid",
    "message": "Bad Request"
   }
  ],
  "code": 400,
  "message": "Bad Request"
 }
}

Followed by a more ordinary stack trace...

EDIT Recently it stopped giving me 400 and instead started giving me 403 Forbidden, still with the domain of usageLimits, reason now being accessNotConfigured and message being Access Not Figured.

Upvotes: 1

Views: 2294

Answers (2)

ArtOfWarfare
ArtOfWarfare

Reputation: 21486

The issue appears to have been that in APIs Console I hadn't turned on both DRIVE SDK and DRIVE API under services. They're separate, and one doesn't automatically turn the other on.

Upvotes: 0

Claudio Cherubino
Claudio Cherubino

Reputation: 15014

You are passing the Client ID you got from the APIs Console to driveRequest.setKey, however that method is used to set an API Key and not the Client ID. That's why your application is not correctly bound to the project from the APIs Console and your app is not allowed to use the API.

Once you get a valid OAuth token for the project identified by that Client ID, you set it by calling driveRequest.setOauthToken(String).

For more details about OAuth2 on Android check http://developer.android.com/training/id-auth/authenticate.html

Upvotes: 2

Related Questions