Why is AccountAuthenticator#getAuthToken() not called?
Asked Answered
L

2

11

I created my own Android account authenticator by extending AbstractAccountAuthenticator and implementing addAccount() and getAuthToken(). Some of the methods in it are called by AccountManager, but others are not.

This works great:

AccountManager#addAccount()

AccountManager accountManager = AccountManager.get(activity);
accountManager.addAccount(MyAccountAuthenticator.ACCOUNT_TYPE,
    MyAccountAuthenticator.AUTHTOKEN_TYPE_FULL_ACCESS, null, null,
    activity, callback, null);

The problem happens when I call AccountManager#getAuthToken() in my Activity. The AccountManager does not call the getAuthToken() method I define in my AccountAuthenticator. It calls some other default method that only checks for existence of an authToken before starting the AuthenticatorActivity.

This does not work. It does not call my getAuthToken() method:

AccountManager#getAuthToken()

AccountManager accountManager = AccountManager.get(activity);
accountManager.getAuthToken(
        mAccount, MyAccountAuthenticator.AUTHTOKEN_TYPE_FULL_ACCESS, null,
        activity, callback, handler);

AuthenticatorService

I created my service and defined onBind(). addAccount() should not work otherwise.

public IBinder onBind(Intent intent) {
    return intent.getAction().equals(ACTION_AUTHENTICATOR_INTENT) ? new MyAccountAuthenticator(this).getIBinder() : null;
}

EDIT: I call addAccountExplicitly in MyAuthenticatorActivity after the app gets an auth token back for the user.

Snippet from class MyAuthenticatorActivity extends AccountAuthenticatorActivity:

if (getIntent().getBooleanExtra(KEY_IS_ADDING_NEW_ACCOUNT, false)) {
    // Creating the account on the device and setting the auth token we recieved
    accountManager.addAccountExplicitly(account, null, null);
}
Leptosome answered 8/1, 2014 at 0:56 Comment(6)
Did you ever use addAccountExplicitly in your activity?Fiske
Yes I call it in my subclass of AccountAuthenticatorActivity. I've added that to an EDIT in the question.Leptosome
If the result of calling getAuthToken is that your login activity is launched, then your authenticator is being called -- Android has no other way to determine what activity to launch than what you return as an Intent. I notice you're adding the account with a null password. Perhaps your implementation short-circuits if it finds a null pass? Post the body of getAuthToken from your authenticator.Fiske
As I mentioned in my question, getAuthToken() is not even called when there is an existing auth token set. It bypasses the call and just returns the auth token, which is not what I expect it to do. How I interpreted the documentation, it should still call my method. I then can decide if I want to return the existing token or get a new one (I check to see if the auth token is expired before returning it).Leptosome
The password is null because I am using OAuth Bearer tokens. No password needs to be set and I never use that field. The getAuthToken method works great when it is actually called, no need to see the source there.Leptosome
Did my answer clear things up?Fiske
F
28

Your comment cleared things up immensely -- if you set the auth token for the account, then your getAuthToken method will not be called until the token is invalidated. You generally do this by calling invalidateAuthToken upon receiving a 401 or 403 or what have you from the web service.

From the Javadoc for the getAuthToken methods:

If a previously generated auth token is cached for this account and type, then it is returned. Otherwise, if a saved password is available, it is sent to the server to generate a new auth token. Otherwise, the user is prompted to enter a password.

Since your token is in the cache, it is returned directly and your authenticator is not consulted.

Fiske answered 31/1, 2014 at 23:25 Comment(6)
Thanks. The docs are very ambiguous about when it calls the authenticator, and when it just calls its own code. I thought my authenticator was expected to implement the functionality described in your quote.Leptosome
No problem -- I agree the authenticator docs are generally pretty poor.Fiske
Moreover, if getAuthToken() successfully returned KEY_AUTHTOKEN once, it is cached automatically (even without any calls to AccountManager.setAuthToken() in your app). So all subsequent calls to AccountManager.getAuthToken() wount result in calling Authenticator.getAuthToken() but just return String token immediately. Tested on Android 4.3 Samsung Note 2.Maidinwaiting
Thank you guys! So why THE HELL peekAuthToken() is there if calling getAuthToken() already does everything for you? I was calling setAuthToken outside the Authenticator, then in my getAuthToken I call peekAuthToken to check whether we have a cached authToken... but it's not called, because getAuthToken already does the job for you, right?Yolandoyolane
this made my day!! That sentence - if you set the auth token for the account, then your getAuthToken method will not be called until the token is invalidated - made me understand everythigHoi
That sentence from the documentation does not make any sense. Because it returns cached token, but it does NOT generate new token if token is invalidated, we have to do it ourselves. It is stupid because I would like to check expiration date so I wouldn't need to make a network call to figure if token is expired. But it is not so convenient to code unless I can code it inside getAuthToken()Septicidal
E
-2

for calling AuthenticatorActivity in method AccountManager#getAuthToken, you must send intent to the activity by parcelable, method for example :

    final Intent intent = new Intent(mContext, LoginActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, accountAuthenticatorResponse);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_TYPE, account.type);
    intent.putExtra(LoginActivity.ARG_AUTH_TYPE, authTokenType);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_NAME, account.name);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);
Elliotelliott answered 20/9, 2014 at 5:10 Comment(1)
This does not answer the question at all.Leptosome

© 2022 - 2024 — McMap. All rights reserved.