Primico
Primico

Reputation: 2445

How to handle refresh tokens with android account manager

I have this method below that syncs data with my server. If I am logged in with a valid auth token, it works fine. But I am unsure how to make it work if the auth token is expired. In my iOS app, I check the "expires_in" value, and if it is expired, I use the refresh token to get a new auth token. But I am not sure how to do the same thing using the account manager. I am not sure where I handle getting the refresh token from the device and sending it to my server to get the new auth token.

Here is a sample method where I get the token:

@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
    Intent i = new Intent("Sync Started");
    mContext.sendBroadcast(i);

    String token = mAccountManager.blockingGetAuthToken(account, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, true);

    // do sync here using token
}

And here is my AbstractAccountAuthenticator -> getAuthToken:

@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
    Bundle result;
    result = AuthHelper.getAccessTokenFromDevice(context, account, authTokenType);
    if (result != null) {
        return result;
    }
    final String refreshToken = AuthHelper.getRefreshTokenFromDevice(context, account);
    if (refreshToken != null) {
        result = AuthHelper.makeResultBundle(account, refreshToken, null);
        return result;
    }
    if (AuthHelper.isAccountAvailable(context, account)) {
        result = AuthHelper.makeResultBundle(account, null, null);
        return result;
    }
    return new Bundle();
}

Upvotes: 3

Views: 2554

Answers (1)

Osvel Alvarez Jacomino
Osvel Alvarez Jacomino

Reputation: 729

I did something like this

public Object getUserInfo(String token){

    try {

        Log.d(TAG, "getUserInfo: "+token);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("token", token);

        HttpEntity<String> request = new HttpEntity<>(null, headers);

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

        ResponseEntity<User> obj = restTemplate.exchange(URL_API_GET_USER_INFO, HttpMethod.GET, request, User.class);

        Log.d(TAG, "getUserInfo: returning User");
        return obj.getBody();
    }
    catch (HttpClientErrorException e){

        if (e.getStatusCode().value() != 403){
            return e.getMessage();
        }

        Log.d(TAG, "getUserInfo: forbidden, my current token is expired");

        //invalidate current token
        AccountManager am = AccountManager.get(mContext);
        am.invalidateAuthToken("cu.jaco.accountexample", token);

        //request new token to my server
        String mNewToken = requestToken();
        if (!StringUtils.isEmpty(mNewToken)){
            //if we get a new token call recursively getUserInfo with new token
            return getUserInfo(mNewToken);
        }

        return e.getMessage();
    }
    catch (RestClientException e){
        e.printStackTrace();
        Log.d(TAG, "getUserInfo: "+e.getMessage());
        return null;
    }
}



private String requestToken(){

    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED) {
        return null;
    }

    AccountManager mAccountManager = AccountManager.get(mContext);
    Account[] acc = mAccountManager.getAccountsByType("cu.jaco.accountexample");

    //AccountAuthenticator is my class that extends form AbstractAccountAuthenticator
    AccountAuthenticator authenticator = new AccountAuthenticator(mContext);
    Bundle bundle;
    try {
        //ask directly for a new token
        bundle = authenticator.getAuthToken(null, acc[0], "cu.jaco.accountexample.user", null);
    } catch (NetworkErrorException e1) {
        e1.printStackTrace();
        return e1.getMessage();
    }

    String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);

    //refresh token in AccountManager
    mAccountManager.setAuthToken(acc[0], "cu.jaco.accountexample.user", token);

    return token;

}

Upvotes: 1

Related Questions