hienlt0610
9/18/2019 - 8:11 AM

Refreshing OAuth token with okhttp interceptors.

private class HttpInterceptor implements Interceptor {

	@Override
	public Response intercept(Chain chain) throws IOException {
		Request request = chain.request();

		//Build new request
		Request.Builder builder = request.newBuilder();
		builder.header("Accept", "application/json"); //if necessary, say to consume JSON
		
		String token = settings.getAccessToken(); //save token of this request for future
		setAuthHeader(builder, token); //write current token to request

		request = builder.build(); //overwrite old request
		Response response = chain.proceed(request); //perform request, here original request will be executed

		if (response.code() == 401) { //if unauthorized
			synchronized (httpClient) { //perform all 401 in sync blocks, to avoid multiply token updates
				String currentToken = settings.getAccessToken(); //get currently stored token

				if(currentToken != null && currentToken.equals(token)) { //compare current token with token that was stored before, if it was not updated - do update

					int code = refreshToken() / 100; //refresh token
					if(code != 2) { //if refresh token failed for some reason
						if(code == 4) //only if response is 400, 500 might mean that token was not updated
							logout(); //go to login screen
						return response; //if token refresh failed - show error to user
					}
				}

				if(settings.getAccessToken() != null) { //retry requires new auth token,
					setAuthHeader(builder, settings.getAccessToken()); //set auth token to updated
					request = builder.build();
					return chain.proceed(request); //repeat request with new token
				}
			}
		}

		return response;
	}
	
	private void setAuthHeader(Request.Builder builder, String token) {
		if (token != null) //Add Auth token to each request if authorized
			builder.header("Authorization", String.format("Bearer %s", token));
	}
	
	private int refreshToken() {
		//Refresh token, synchronously, save it, and return result code
		//you might use retrofit here
	}
	
	private int logout() {
		//logout your user
	}
}
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";
    }

}