package com.example.yourapp; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.example.yourapp.AuthenticationModel; import retrofit.client.Header; import retrofit.client.OkClient; import retrofit.client.Request; import retrofit.client.Response; /** * Extends the default Retrofit Http client with a check if the request got denied because the OAuth * token expired. In this case * To be entirely sure that there will be no StackOverFlowErrors using this implementation * Don't let your authentication model use this as a client. **/ public class OAuthClient extends OkClient { private AuthenticationModel _authModel; public OAuthClient(AuthenticationModel authModel){ _authModel = authModel; } /** * Replaces the access token with the new one in the request. * @param request Input request to modify * @return An other request with the same parameters, but the replaced authorization header */ private Request changeTokenInRequest(Request request){ List<Header> tempHeaders = request.getHeaders(); // this one is an unmodifiable list. List<Header> headers = new ArrayList<Header>(); headers.addAll(tempHeaders); // this one is modifiable Iterator<Header> iter = headers.iterator(); boolean hadAuthHeader = false; // we check if there was an authentication header in the original request while(iter.hasNext()){ Header h = iter.next(); if (h.getName().equals("Authorization")){ iter.remove(); hadAuthHeader = true; } } // if there was an authentication header, replace it with another one containing the new access token. if (hadAuthHeader){ headers.add(new Header("Authorization", "Bearer " + _authModel.getAccessToken())); } // everything stays the same, except the headers return new Request(request.getMethod(), request.getUrl(), headers, request.getBody()); } @Override public Response execute(Request request) throws IOException { Response response = super.execute(request); // 401: Forbidden, 403: Permission denied if (response.getStatus() == 401 || response.getStatus() == 403) { // the next call should be a synchronous call, otherwise it will immediately continue, and use the old token instead. _authModel.refreshToken(); // the headers should be modified because the access token changed Request newRequest = changeTokenInRequest(request); return super.execute(newRequest); } else { return response; } } }