Last active
March 15, 2022 04:42
-
-
Save CarolusX74/057dbf4d8de3095873b15956bdf47935 to your computer and use it in GitHub Desktop.
How I automatically refresh OAuth "access token" with okhttp interceptors using "refresh token". All requests will wait until token refresh finished, and then will continue with the new token. - EN (By Carlos Torres)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.cjtp.android.api.interceptors; | |
import android.util.Log; | |
import com.google.gson.JsonObject; | |
import com.inviteez.android.core.Session; | |
import com.inviteez.android.utils.Constant; | |
import org.json.JSONException; | |
import org.json.JSONObject; | |
import java.io.IOException; | |
import okhttp3.Interceptor; | |
import okhttp3.MediaType; | |
import okhttp3.OkHttpClient; | |
import okhttp3.Request; | |
import okhttp3.RequestBody; | |
import okhttp3.Response; | |
import static com.cjtp.android.utils.Constant.TAG_ALIEN; | |
import static com.cjtp.android.utils.Constant.URL_ENDPOINT_TOKEN_REFRESH; | |
/** | |
* Created by CJ on 26/6/2017. | |
*/ | |
public class AuthTokenRefreshInterceptor implements Interceptor { | |
private static final String TAG_THIS = AuthTokenRefreshInterceptor.class.getSimpleName(); | |
//--- HTTP Response codes relative constants | |
private static final int RESPONSE_UNAUTHORIZED_401 = 401; | |
private static final int RESPONSE_HTTP_RANK_2XX = 2; | |
private static final int RESPONSE_HTTP_CLIENT_ERROR = 4; | |
private static final int RESPONSE_HTTP_SERVER_ERROR = 5; | |
//--- My backend params | |
private static final String BODY_PARAM_KEY_GRANT_TYPE = "grant_type"; | |
private static final String BODY_PARAM_VALUE_GRANT_TYPE = "refresh_token"; | |
private static final String BODY_PARAM_KEY_REFRESH_TOKEN = "refresh_token"; | |
@Override | |
public Response intercept(Chain chain) throws IOException { | |
Request request = chain.request(); //<<< Original Request | |
//Build new request----------------------------- | |
Request.Builder builder = request.newBuilder(); | |
builder.header("Accept", "application/json"); //if necessary... | |
String token = Session.getAccessToken(); //Save token of this request for future | |
setAuthHeader(builder, token); //Add Current Authentication Token.. | |
request = builder.build(); //Overwrite the original request | |
Log.d(Constant.TAG_ALIEN + TAG_THIS, | |
">>> Sending Request >>>\n" | |
+"To: "+request.url()+"\n" | |
+"Headers:"+request.headers()+"\n" | |
+"Body: "+bodyToString(request)); //Shows the magic... | |
//------------------------------------------------------------------------------------------ | |
Response response = chain.proceed(request); // Sends the request (Original w/ Auth.) | |
//------------------------------------------------------------------------------------------ | |
Log.d(Constant.TAG_ALIEN + TAG_THIS, | |
"<<< Receiving Request response <<<\n" | |
+"To: "+response.request().url()+"\n" | |
+"Headers: "+response.headers()+"\n" | |
+"Code: "+response.code()+"\n" | |
+"Body: "+bodyToString(response.request())); //Shows the magic... | |
//------------------- 401 --- 401 --- UNAUTHORIZED --- 401 --- 401 ------------------------- | |
if (response.code() == RESPONSE_UNAUTHORIZED_401) { //If unauthorized (Token expired)... | |
Log.w(TAG_ALIEN + TAG_THIS,"Request responses code: "+response.code()); | |
synchronized (this) { // Gets all 401 in sync blocks, | |
// to avoid multiply token updates... | |
String currentToken = Session.getAccessToken(); //Get currently stored token (...) | |
//Compares current token with token that was stored before, | |
// if it was not updated - do update.. | |
if(currentToken != null && currentToken.equals(token)) { | |
// --- REFRESHING TOKEN --- --- REFRESHING TOKEN --- --- REFRESHING TOKEN ------ | |
int code = refreshToken() / 100; //Refactor resp. cod ranking | |
if(code != RESPONSE_HTTP_RANK_2XX) { // If refresh token failed | |
if(code == RESPONSE_HTTP_CLIENT_ERROR // If failed by error 4xx... | |
|| | |
code == RESPONSE_HTTP_SERVER_ERROR ){ // If failed by error 5xx... | |
logout(); // ToDo GoTo login screen | |
return response; // Todo Shows auth error to user | |
} | |
} // <<--------------------------------------------New Auth. Token acquired -- | |
} // <<-----------------------------------New Auth. Token acquired double check -- | |
// --- --- RETRYING ORIGINAL REQUEST --- --- RETRYING ORIGINAL REQUEST --- --------| | |
if(Session.getAccessToken() != null) { // Checks new Auth. Token | |
setAuthHeader(builder, Session.getAccessToken()); // Add Current Auth. Token | |
request = builder.build(); // O/w the original request | |
Log.d(Constant.TAG_ALIEN + TAG_THIS, | |
">>> Retrying original Request >>>\n" | |
+"To: "+request.url()+"\n" | |
+"Headers:"+request.headers()+"\n" | |
+"Body: "+bodyToString(request)); //Shows the magic... | |
//-----------------------------------------------------------------------------| | |
Response responseRetry = chain.proceed(request);// Sends request (w/ New Auth.) | |
//-----------------------------------------------------------------------------| | |
Log.d(Constant.TAG_ALIEN + TAG_THIS, | |
"<<< Receiving Retried Request response <<<\n" | |
+"To: "+responseRetry.request().url()+"\n" | |
+"Headers: "+responseRetry.headers()+"\n" | |
+"Code: "+responseRetry.code()+"\n" | |
+"Body: "+bodyToString(response.request())); //Shows the magic. | |
return responseRetry; | |
} | |
} | |
}else { | |
//------------------- 200 --- 200 --- AUTHORIZED --- 200 --- 200 ----------------------- | |
Log.w(TAG_ALIEN + TAG_THIS,"Request responses code: "+response.code()); | |
} | |
return response; | |
} | |
// Sets/Adds the authentication header to current request builder.-----------------------------| | |
private void setAuthHeader(Request.Builder builder, String token) { | |
Log.i(TAG_ALIEN + TAG_THIS,"Setting authentication header..."); | |
if (token != null){ | |
builder.header("Authorization", String.format("Bearer %s", token)); | |
} | |
Log.w(TAG_ALIEN + TAG_THIS, "Current Auth Token = "+Session.getAccessToken()); | |
Log.w(TAG_ALIEN + TAG_THIS, "Current Refresh Token = "+Session.getRefreshAccessToken()); | |
} | |
// Refresh/renew Synchronously Authentication Token & refresh token----------------------------| | |
private int refreshToken() { | |
Log.w(TAG_ALIEN+TAG_THIS,"Refreshing tokens... ;o"); | |
// Builds a client... | |
OkHttpClient client = new OkHttpClient.Builder().build(); | |
// Builds a Request Body...for renewing token... | |
MediaType jsonType = MediaType.parse("application/json; charset=utf-8"); | |
JsonObject json = new JsonObject(); | |
//--- | |
json.addProperty(BODY_PARAM_KEY_GRANT_TYPE, BODY_PARAM_VALUE_GRANT_TYPE); | |
json.addProperty(BODY_PARAM_KEY_REFRESH_TOKEN,Session.getRefreshAccessToken()); | |
//--- | |
RequestBody body = RequestBody.create(jsonType,json.toString()); | |
// Builds a request with request body... | |
Request request = new Request.Builder() | |
.url(Constant.URL_SERVER+URL_ENDPOINT_TOKEN_REFRESH) | |
.post(body) //<<<--------------Adds body (Token renew by the way) | |
.build(); | |
Response response = null; | |
int code = 0; | |
Log.d(Constant.TAG_ALIEN + TAG_THIS, | |
">>> Sending Refresh Token Request >>>\n" | |
+"To: "+request.url()+"\n" | |
+"Headers:"+request.headers()+"\n" | |
+"Body: "+bodyToString(request)); //Shows the magic... | |
try { | |
//-------------------------------------------------------------------------------------- | |
response = client.newCall(request).execute(); //Sends Refresh token request | |
//-------------------------------------------------------------------------------------- | |
Log.d(Constant.TAG_ALIEN + TAG_THIS, | |
"<<< Receiving Refresh Token Request Response <<<\n" | |
+"To: "+response.request().url()+"\n" | |
+"Headers:"+response.headers()+"\n" | |
+"Code: "+response.code()+"\n" | |
+"Body: "+bodyToString(response.request())); //Shows the magic... | |
if (response != null) { | |
code = response.code(); | |
Log.i(TAG_ALIEN + TAG_THIS,"Token Refresh responses code: "+code); | |
switch (code){ | |
case 200: | |
// READS NEW TOKENS AND SAVES THEM ----------------------------------------- | |
try { | |
//Log.i(TAG_ALIEN+TAG_THIS,"Decoding tokens start"); | |
JSONObject jsonBody = null; | |
jsonBody = new JSONObject(response.body().string()); | |
String newAuthtoken = jsonBody.getString("access_token"); | |
String tokenRefresh = jsonBody.getString("refresh_token"); | |
Log.i(TAG_ALIEN+TAG_THIS,"New Access Token = "+newAuthtoken); | |
Log.i(TAG_ALIEN+TAG_THIS,"New Refresh Token = "+tokenRefresh); | |
Session.setAccessToken(newAuthtoken); | |
Session.setRefreshAccessToken(tokenRefresh); | |
//Log.i(TAG_ALIEN+TAG_THIS,"Decoding tokens finish."); | |
} catch (JSONException e) { | |
Log.w(TAG_ALIEN + TAG_THIS,"Responses code "+ code | |
+" but error getting response body.\n" | |
+ e.getMessage()); | |
} | |
break; | |
default: | |
// READS ERROR ------------------------------------------------------------- | |
try { | |
//Log.i(TAG_ALIEN+TAG_THIS,"Decoding error start"); | |
JSONObject jsonBodyE = null; | |
jsonBodyE = new JSONObject(response.body().string()); | |
String error = jsonBodyE.getString("error"); | |
String errorDescription = jsonBodyE.getString("error_description"); | |
//Log.i(TAG_ALIEN+TAG_THIS,"Decoding tokens finish."); | |
} catch (JSONException e) { | |
Log.w(TAG_ALIEN + TAG_THIS,"Responses code "+ code | |
+" but error getting response body.\n" | |
+ e.getMessage()); | |
e.printStackTrace(); | |
} | |
break; | |
} | |
response.body().close(); //ToDo check this line | |
} | |
} catch (IOException e) { | |
Log.w(TAG_ALIEN + TAG_THIS,"Error while Sending Refresh Token Request\n"+e.getMessage()); | |
e.printStackTrace(); | |
} | |
//Log.w(TAG_ALIEN,"Refresh Token request responses code? = "+code); | |
return code; | |
} | |
private int logout() { | |
Log.d(TAG_ALIEN+TAG_THIS,"go to logout"); | |
//logout your user | |
return 0; //TODO... | |
} | |
//---------------------------------------------------------------------------------------------- | |
@Deprecated | |
private static String bodyToString(final Request request){ | |
/* | |
try { | |
final Request copy = request.newBuilder().build(); | |
final Buffer buffer = new Buffer(); | |
copy.body().writeTo(buffer); | |
return buffer.readUtf8(); | |
} catch (final IOException e) { | |
Log.w(TAG_ALIEN+TAG_THIS,"Error while trying to get body to string."); | |
return "Null"; | |
}*/ | |
return "Nullix"; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello, I am having some troubles refreshing token on Spotify - Android.
Could you check my question on stackoverflow?
Thank you.