1

I'm developing an Android app which is using Oauth2 tokens to get authorization in order to access secured resources. I'm using a third party platform as the authentication server (using OpenId Connect). Basically my problem is that I want to deal with an expired refresh token.

Current scenario

I've got a NetUtils class which acts like a singleton and manages all my requests using a secured rest template. That rest template injects the required Authorization header for each request using a request wrapper. The NetUtils class deals whith tokens and timeouts, saving them in user preferences and refreshing them when it's needed.

However, the problem comes when the refresh token itself expires. As I'm using the Authorization code flow, I need to open a WebView and redirect the user to the login page, but I notice it when the NetUtils class determinates the refresh token has expired. Ideally, the app would launch a WebView, the user would login again and the stored request would be executed. Here it is my code to refresh the access token:

private AccessToken refreshToken(String idClient, String clientSecret, AccessToken accessToken) {
    MultiValueMap<String, String> clientAuthenticationForm = new LinkedMultiValueMap<>();
    clientAuthenticationForm.add("grant_type", "refresh_token");
    clientAuthenticationForm.add("refresh_token", accessToken.getRefreshToken());
    clientAuthenticationForm.add("client_id", idClient);
    clientAuthenticationForm.add("client_secret", clientSecret);
    try {
        long lastClientRefresh = mPrefs.getLong(Preferences.LAST_LOGIN_TIME, Long.MIN_VALUE);
        boolean refreshTokenExpired = lastClientRefresh
                + TimeUnit.SECONDS.toMillis(accessToken.getRefreshExpiresIn()) < System
                .currentTimeMillis();
        if (!refreshTokenExpired) {
            return regularRestTemplate
                    .postForEntity(tokenUrl(), clientAuthenticationForm, AccessToken.class)
                    .getBody();
        }else{
            //How to cope with this?
            return null;
        }
    } catch (Exception ex) {
        Log.e(TAG, ex.getMessage(), ex);
        throw ex;
    }
}

Other choice

Other choice would be to make the refresh token long lived and refresh it each time the app starts, for example. I have to mention that client_id and client_secret are currently being hardcoded in the app (although client credential grants are not meant to be enabled in production, so there's still the need to provide a username and password to retrieve a token).

What would be the best practice here?

Xtreme Biker
  • 28,480
  • 12
  • 120
  • 195

1 Answers1

2

I think I can't suggest you how to code in Java, but I also had some troubles with refresh_token while creating application in PHP so maybe my thoughts will help you with something.

At first I was looking for refresh_token which never expires (like in Google API) so I can even hardcode it and use whenever I want to create a new access_token. Anyway it's really hard to do in oAuth2. So I have found a interesting look on this problem here:

Why do access tokens expire?

It showed me a bit other way to work with refresh_token. I have set on my oAuth service that it generates and returns a new refresh_token everytime I use refresh_token to obtain a new access_token. That part helped me most:

https://bshaffer.github.io/oauth2-server-php-docs/grant-types/refresh-token/

And there we got something like:

$server = new OAuth2\Server($storage, array(
    'always_issue_new_refresh_token' => true, // this part
    'refresh_token_lifetime'         => 2419200,
));

In this case I have a long live refresh_token which I can store somewhere and when I need it I will use it to get a new access_token, but response will also provide me a new refresh_token which I can store again and use it later for obtaining a new access_token.

So in your case I think the best way is to keep generating refresh_token everytime you ask for access_token with refresh_token. And if user will not use your APP for longer time, I think he should authorize himself again.

Community
  • 1
  • 1
Karol Gasienica
  • 2,479
  • 18
  • 32