I tried to follow tutorial: https://developers.google.com/android/guides/http-auth.
Code:
token = GoogleAuthUtil.getToken(getApplicationContext(),
Try following the Drive quickstart for Android, it is a step-by-step guide showing how to authorize and upload a file to Drive: https://developers.google.com/drive/quickstart-android
To be more specific, it looks like you are not catching the UserRecoverableException and triggering the intent to have the user authorize the app. This is documented in the Google Play Services docs you linked and handled in the quickstart sample as follows:
...
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
}
...
On this docs page https://developers.google.com/+/mobile/android/sign-in the example has a good explanation for this exception.
In particular, it looks like this line should be noted:
Requesting an authorization code will always throw UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
catch (UserRecoverableAuthException e) {
// 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.
startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
return;
}
the method getAndUseAuthTokenBlocking() of the official GoogleAuthUtil tutorial explains pretty well how to handle the exception:
// Example of how to use the GoogleAuthUtil in a blocking, non-main thread context
void getAndUseAuthTokenBlocking() {
try {
// Retrieve a token for the given account and scope. It will always return either
// a non-empty String or throw an exception.
final String token = GoogleAuthUtil.getToken(Context, String, String)(context, email, scope);
// Do work with token.
...
if (server indicates token is invalid) {
// invalidate the token that we found is bad so that GoogleAuthUtil won't
// return it next time (it may have cached it)
GoogleAuthUtil.invalidateToken(Context, String)(context, token);
// consider retrying getAndUseTokenBlocking() once more
return;
}
return;
} catch (GooglePlayServicesAvailabilityException playEx) {
Dialog alert = GooglePlayServicesUtil.getErrorDialog(
playEx.getConnectionStatusCode(),
this,
MY_ACTIVITYS_AUTH_REQUEST_CODE);
...
} catch (UserRecoverableAuthException userAuthEx) {
// Start the user recoverable action using the intent returned by
// getIntent()
myActivity.startActivityForResult(
userAuthEx.getIntent(),
MY_ACTIVITYS_AUTH_REQUEST_CODE);
return;
} 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 (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
...
return;
}
}
I found the answers here are passive solutions and not preventive.
According to my very short experience, UserRecoverableAuthException: NeedPermission will be thrown in the following 3 cases:
#1 Appropriate Scope is not requested when signing in to Google
Check that the scopes you are requesting are correct. Android should ask the user to allow permission after the authentication process via permission request dialog. This will prevent UserRecoverableAuthException when calling API.
GoogleSignInOptions o = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(DriveScopes.DRIVE)) // request permission for Drive API
.requestScopes(new Scope(SheetsScopes.SPREADSHEETS)) // request permission for Sheets API
.requestEmail()
.build();
#2 User has denied permission
The user has pushed "DENY" button on permission request dialog.
#3 User has rejected permissions from your app
As for Android 8.1.x, there is a menu where you can reject permissions for individual apps. Not sure about other versions, though.
Settings > Google > Connected apps
UserRecoverableAuthException thrown by #2 and #3 is unavoidable because those are the result of user activity. But isn't that meaningless to show permission request dialog again with below code despite the user's rejection?
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
}
I had the same error, in my case I was using a wrong scope, I just change
https://www.googleapis.com/auth/plus.login
for
https://www.googleapis.com/auth/userinfo.profile
The docs have been recently updated and now work to support SDK M(requesting permission) and also show the OAuth dialog.
NOTE Google Docs are often not up to date but they seem to pay attention when you report an issue. The example was updated with a week of me sending a feedback. So if you see a non-working example, send feedback!
https://developers.google.com/drive/v3/web/quickstart/android