Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redo previous request when the first fails with 401 Unauthorized

I'm building an Android application that will fetch data from a REST API.

To make the requests I'm using Retrofit together with Otto.

For all my requests I add a RequestInterceptor that will add a header (Authorization) to all my requests. In the RequestInterceptor I'm calling a method to the my current access_token then I populate the header to the request.

RequestInterceptor requestInterceptor = new RequestInterceptor() {

    @Override
    public void intercept(RequestFacade request) {
        Token token = TokenPreferences.getToken();

        request.addHeader("Authorization", token.getTokenType() + " " + token.getAccessToken());
    }
};

RestAdapter restAdapter = new RestAdapter.Builder()
      .setEndpoint("https://example.com")
      .setRequestInterceptor(requestInterceptor)
      .build();

  ...

This works fine until the access_token has expired, then the request will fail with HTTP status 401 Unauthorized. When this happens, I want to make a new request to get a new access_token from my refresh_token I got and then do the first request again.

I'm not really sure how to make that work.

like image 483
BratAnon Avatar asked Oct 31 '22 18:10

BratAnon


1 Answers

Try a com.squareup.okhttp.Authenticator. As far as I can tell, this is preferable to com.squareup.okhttp.Interceptor (which you'll find suggested elsewhere), because it will only kick in for unauthorized requests. Here's a basic example:

public class ApiAuthenticator implements Authenticator {

    @Override
    public Request authenticate(Proxy proxy, Response response) throws IOException {
        for (Challenge challenge : response.challenges()) {
            if (challenge.getScheme().equals("Bearer")) {

                String authToken = // Refresh the token here

                if (authToken != null) {
                    return response.request().newBuilder()
                            .header("Authorization", "Bearer " + authToken)
                            .build();
                }
            }
        }
        return null;
    }

    @Override
    public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
        return null;
    }
}

You can attach it to your client like this:

okHttpClient.setAuthenticator(new ApiAuthenticator());

Be aware that if you're using Retrofit to refresh your token and the token is invalid, you might get unexpected, hard-to-debug behavior for 403 codes, but the solution is just to use a try/catch block.

try {
    token = oauthService.refreshAccessToken(args);
} catch (RetrofitError error) {
    // Do something that leads to login
}
like image 63
Jimeux Avatar answered Nov 08 '22 14:11

Jimeux