Skip to content

Instantly share code, notes, and snippets.

@shercoder
Forked from dzolnai/OAuthClient.java
Created May 4, 2014 19:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shercoder/9489516dcb750d7f4461 to your computer and use it in GitHub Desktop.
Save shercoder/9489516dcb750d7f4461 to your computer and use it in GitHub Desktop.
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;
}
}
}
// Create your RestAdapter this way
RestAdapter adapter = new Builder()
.setEndpoint(endpoint)
.setClient(new OAuthClient(yourAuthModel)
...
.build();
// Util to convert TypedInput to Java String
public static String stringFromTypedInput(TypedInput input) {
try {
InputStream istream = input.in();
java.util.Scanner s = new java.util.Scanner(istream).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
} catch (IOException e) {
return null;
}
}
// Example call
private interface OAuthInterface {
@FormUrlEncoded
@POST("/oauth2/access_token")
public void getAccessToken(@Field("username") String username, @Field("password") String password, @Field("client_id") String clientId, @Field("client_secret") String clientSecret, @Field("grant_type") String grantType,
Callback<TokenData> cb);
// NOTICE: This call is synchronous! This should only be called from the OAuthClient.
@FormUrlEncoded
@POST("/oauth2/access_token")
public String refreshToken(@Field("refresh_token") String refreshToken, @Field("client_id") String clientId, @Field("client_secret") String clientSecret, @Field("grant_type") String grantType);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment