Search code examples
androidfirebasefirebase-authenticationretrofit2access-token

How to send updated Firebase Token with every Retrofit API call


I want to send updated token (FirebaseAuth.getInstance().getAccessToken()) every time I need to send my REST request in Header via Retrofit. I have setup the RetrofitClient as following-

RetrofitClient.java

public class RetrofitClient {

    private static final String BASE_URL = "API_URL";
    private static RetrofitClient mInstance, mAuthInstance;
    private Retrofit retrofit;

    private RetrofitClient(boolean requireAuthorization, String firebaseID, Context context){

        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        //Put Custom Header i.e. 'InterceptorHeader' in all API request
        OkHttpClient okHttpClient;

        if(requireAuthorization)
            okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(new ConnectivityInterceptor(context))               // Header to check internet connectivity
                    .addInterceptor(new AuthorizationInterceptorHeader(firebaseID))     // Header Auth InterceptorHeader
                    .addInterceptor(loggingInterceptor).build();                        // Header for logging
        else
            okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(new ConnectivityInterceptor(context))    // Header to check internet connectivity
                    .addInterceptor(new InterceptorHeader())                 // Header InterceptorHeader
                    .addInterceptor(loggingInterceptor).build();             // Header for logging


        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(okHttpClient) //adding custom OkHttp Client
                .build();
    }

    public static synchronized RetrofitClient getInstance(Context context){
        if(mInstance == null){
            mInstance = new RetrofitClient(false, null, context);
        }
        return mInstance;
    }

    public static synchronized RetrofitClient getAuthInstance(boolean requireAuthorization, String firebaseID, Context context){
        if(mAuthInstance == null){
            mAuthInstance = new RetrofitClient(requireAuthorization, firebaseID, context);
        }
        return mAuthInstance;
    }

    public TurnoAPI getTurnoApi(){
        return retrofit.create(TurnoAPI.class);
    }

}

AuthorizationInterceptorHeader.java

public class AuthorizationInterceptorHeader implements Interceptor {

    String firebaseID;

    public AuthorizationInterceptorHeader(String firebaseID) {
        this.firebaseID = firebaseID;
    }

    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {

        Request originalRequest = chain.request();

        //TODO change request header
        Request newRequest = originalRequest.newBuilder()
                .addHeader("Content-Type", "application/json")
                .addHeader("api-key", "api_key")
                .addHeader("api-hash", "api_key")
                .addHeader("**Authorization**", "FIREBASE_TOKEN")
                .build();
        return chain.proceed(newRequest);
    }
}

I want to send FirebaseAuth.getInstance().getCurrentUser().getIdToken() in Header saying Authorization. now because getIdToken() is returning a task so I am not sure how I need to setup to make every auth request with updated Firebase Token, any workaround would be appreciated. Thanks.


Solution

  • This could be my bad that I have not framed my question correctly. But I found the solution and I posting it so that it might help someone.

    Reframe Question

    I was trying to send the FirebaseTokenID(JWT) with my every REST API request. I was not keeping a local copy of tokenID because tokenID has a short life of 1 hour. To get the JWT from Firebase there is following method-

    FirebaseAuth.getInstance().getCurrentUser().getIdToken()
    

    but this will return a task so I have to manage the call for getIDToken() and wait untill the returning task is complete before I call my API method.

    To solved this I used the interface to make the calls.

    TokenListener.java

    public interface TokenListener {
    
        void getToken(String firebaseToken);
    }
    

    FirebaseToken.java

    public class FirebaseToken {
    
        public static void getFirebaseToken(TokenListener tokenListener){
            FirebaseAuth.getInstance().getCurrentUser().getIdToken(false)
                    .addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
                        @Override
                        public void onComplete(@NonNull Task<GetTokenResult> task) {
                            if(task.isSuccessful())
                                tokenListener.getToken(task.getResult().getToken());
                        }
                    });
        }
    }
    

    now from every class who is calling API and need TokenID I was implementing TokenListener to get the current/active tokenID(JWT) and pass on to call my API method to use that as a param to header via AuthorizationInterceptorHeader adding in RetrofitClient class.

    AuthorizationInterceptorHeader.java

    public class AuthorizationInterceptorHeader implements Interceptor {
    
        String firebaseToken;
    
        public AuthorizationInterceptorHeader(String firebaseToken) {
            this.firebaseToken = firebaseToken;
        }
    
        @NotNull
        @Override
        public Response intercept(@NotNull Chain chain) throws IOException {
    
            Request originalRequest = chain.request();
    
            Request newRequest = originalRequest.newBuilder()
                    .addHeader("Content-Type", "application/json")
                    .addHeader("api-key", "api-key")
                    .addHeader("api-hash", "api-hasg")
                    .addHeader("Authorization", firebaseToken)
                    .build();
            return chain.proceed(newRequest);
        }
    }
    

    Happy coding !!