Foenix
Foenix

Reputation: 558

Properly implement AccountManager, oauth-2 and expired token

I am struggling with Account manager and OAuth-2 for some time, I have already implemented AccountManager (with service and account authenticator), Login activity with webview, etc. I implemented all oauth-2 flow, when user enters its credentials on webview, and I save access token as AccountManager password. The last thing I do now know how correctly implement the flow when I do an http-request to server, and its responce is Json with

{"message":"access_token_is_expired","error":true....}

so I should read this responce, analize it and do another request with resresh token to get another access token. How correctly implements this? Where? In what class? May be my Authenticator.getAuthToken method should be improved? this is the code:

@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
        String authTokenType, Bundle loginOptions) throws NetworkErrorException {
    Log.v(TAG, "getAuthToken()");

    if (!authTokenType.equals(Const.AUTHTOKEN_TYPE)) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType");
        return result;
    }

    final AccountManager am = AccountManager.get(mContext);
    final String auth_token = am.getPassword(account);
    if (auth_token != null) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, Const.ACCOUNT_TYPE);
        result.putString(AccountManager.KEY_AUTHTOKEN, auth_token);
        return result;
    }

    final Intent intent = new Intent(mContext, LoginActivity.class);
    intent.putExtra(Const.KEY_SERVER, am.getUserData(account, Const.KEY_SERVER));
    //intent.putExtra(LoginActivity.PARAM_AUTHTOKEN_TYPE, authTokenType);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);
    return bundle;
}

 @Override
protected JSONObject doInBackground(Void... params) {
        InputStream is = null;
        try {                
            String url = "...";
            URL obj = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) obj.openConnection();                
            conn.setRequestMethod("POST");
            conn.setDoOutput(true); 
            String urlParameters = "access_token=" + mToken;
            DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
            wr.writeBytes(urlParameters);
            wr.flush();
            wr.close();
            conn.connect(); 
            int response_code = conn.getResponseCode();
            is = conn.getInputStream();
            String str_response = NetworkUtilities.readStreamToString(is, 500);

            JSONObject response = new JSONObject(str_response);
            return response;


        } catch (MalformedURLException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

I did a huge work to understand this, but I failure.

Upvotes: 1

Views: 1660

Answers (1)

Foenix
Foenix

Reputation: 558

After several days and because of luck of information in the Net, I read codes on github and did some researches. In order to help somebody like me:

The expired token can be reasked in getAuthToken method above, but adding in Bundle (loginOptions) information that it should be reasked from server (for example, as "forceReauth" = true ) I check this parameter inside method and ask the method (2nd peace of code above), otherwize I use usual flow.

The second important thing - one row of code, that I see in here Why is AccountAuthenticator#getAuthToken() not called? God bless Tom G (I cannot add him a vote, because of luck of my reputation). The line of code with invalidateAuthToken BEFORE getAuthToken did everything for me. Add him a vote for me, if you found this useful.

Upvotes: 4

Related Questions