19

We're under Android (Jellybean and higher), and we've got an app which need to use OAuth2 with Google for authentication.

I simplified the login activity, but it's looking like that:

AccountManager mAccountManager;
// [...]
Account account = new Account("myEmail@gmail.com", "com.google");
// same with professional email managed by Google as myEmail@myDomain.com
// real code recovers accounts with mAccountManager.getAccountsByType("com.google")
mAccountManager = AccountManager.get(getBaseContext());
mAccountManager.getAuthToken(account, "oauth2:https://www.googleapis.com/auth/userinfo.email", null, MyActivity.this, new AccountManagerCallback<Bundle>() {
    @Override
    public void run(AccountManagerFuture<Bundle> accountManagerFuture) {
        try {
            String token = accountManagerFuture.getResult().getString(AccountManager.KEY_AUTHTOKEN);
            // exception occurs here
            // [...]
        } catch (Exception e) {
            Log.e("account", "exception occurs", e);
        }
    }
}, null);

When we call accountManagerFuture.getResult(), it fires this exception:

android.accounts.AuthenticatorException: UNREGISTERED_ON_API_CONSOLE
    at android.accounts.AccountManager.convertErrorToException(AccountManager.java:2024)
    at android.accounts.AccountManager.access$400(AccountManager.java:144)
    at android.accounts.AccountManager$AmsTask$Response.onError(AccountManager.java:1867)
    at android.accounts.IAccountManagerResponse$Stub.onTransact(IAccountManagerResponse.java:69)
    at android.os.Binder.execTransact(Binder.java:446)

I cannot find neither doc about this nor other people with the same exception, and I'm quite confused: the call to AccountManager.getAuthToken only provides an account (name and type), a scope, and a callback method, there's no parameter to specify an app or something I could customize in the dev API console.

I'm sure I'm missing something, but what?

Xavier Portebois
  • 3,354
  • 6
  • 33
  • 53

6 Answers6

36

Well, I finally figured it out. Not sure if I misread the documentation or if there are missing links, but anyway.

Fact is that when you sign a APK and then ask Google for a OAuth2 token, you have to register your signed app through the dev console. It's a security measure based on the app package name and the sha1 fingerprint.

To do that, you have to :

  1. sign your APK, manually or through Gradle or whatever: the Android documentation is pretty clear on this step;
  2. get your sha1 fingerprint; as mention in this SO answer, it's kind of easy on Android Studio: in the Gradle panel, select the signingReport task under your root project and run it - the SHA1 fingerprint will show in the text output;
  3. register your APK through the Google dev console: create a new Credentials / OAuth client id / Android, defined by the SHA1 fingerprint you got and your APK package name.

And voila!

For information, the only official documentation I found explaining the why and how of the two final steps is here: https://developers.google.com/drive/android/auth

Community
  • 1
  • 1
Xavier Portebois
  • 3,354
  • 6
  • 33
  • 53
  • 1
    This is a recent change by Google. I had an app that was working in production, targeting API 22, that did something similar to yours. I never made an oauth key for the app. It stopped working sometime between October and December 2016. Additionally, Google *deleted* the manifest permission USE_CREDENTIALS in API 23, but my app still worked on such devices earlier last year. Creating an oauth key for the app resolved my issue. – rockgecko Feb 28 '17 at 10:08
  • @rockgecko i did same but still unable to login with google, can you please explain it ? – JosephM Jun 07 '17 at 12:51
  • i am same following this step but i am getting invlid request what i am missing here Error: invalid_request Invalid parameter value for redirect_uri: Missing scheme: accounts.google.com/o/oauth2/auth – Mehul Tank Sep 18 '18 at 13:45
  • This is well explained but also see Itaki Hanski's answer below for the production apps. The Keystore you use to upload the app is different than the signing app. – MG Developer Nov 03 '18 at 00:31
15

For anyone still struggling with this, here's what worked for me:

If you enroll your app into the Google Play App Signing program, then your KeyStore is not used de facto to sign the application once it reaches the play store - that's why the fingerprints don't match.

Google removes your certificate and creates a new signing certificate that is used to sign your APK.

In the Play Console go to Release Management -> App signing

If you opted in to Google Play App Signing, you'll see 2 certificates there along with all of their fingerprints. Use the App Signing Certificate fingerprint instead of the Upload Certificate which is your KeyStore.

Itai Hanski
  • 8,540
  • 5
  • 45
  • 65
10

Don't have the reputation to comment on the accepted answer...

Registering my app in the google dev console wasn't working for me. It turned out that since I was using the debug gradle build, I had to append ".debug" to the package name in google dev console.

I found this out by debugging the Android AccountManager code. When I stepped into the code, I noticed the variable for my app's package name had ".debug" at the end of it. So instead of using the actual package name "com.package.name" in the google dev console, I changed it to "com.package.name.debug" which fixed the UNREGISTERED_ON_API_CONSOLE exception for me.

The reason for this is because my debug buildType in gradle had 'applicationIdSuffix ".debug"'.

Jeff Angelini
  • 103
  • 1
  • 5
  • This answer was a life saver! I was following every single guide online exactly, with no luck. I had applicationIdSuffix ".staging" in my gradle config, and adding that suffix to the API console fixed everything! – Westy92 Jul 18 '18 at 18:21
1

Thanks Xavier Portebois, your answer really helped. I had to do two more steps.

  • Make sure you enable the API for the service you are using (in my case the Calendar API) in that same google dev console
  • If you are using Google Play App Signing, you do not want to use the debug SHA fingerprint from Android Studio. Instead, go to your app publishing console -> release management -> app signing. Use the SHA-1 fingerprint from the App Signing certificate. 2nd line in this screenshot

Thanks for the informative answer!

Emilie
  • 66
  • 3
0

For me, the solutions above don't work at all. I finally figure out the bug by myself. I have several folders in my work space and each of them has their own Manifest.xml file, which means their have different package names. In this case, when we register on Google API, we have to use the package name in file build.gradle, the property applicationId. Then here it is.

0

For me, the problem was Signing-certificate fingerprint (SHA-1) of the debug app and the release app does not match when I upgrade app and change package name. I've wasted days checking package name then figure out the problem is the package name.

To get correct SHA-1 key, follow this S.O post, then use this key to create a new OAuth client ID for your app.

nhoxbypass
  • 9,695
  • 11
  • 48
  • 71