1

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.

Nikhil Sharma
  • 897
  • 1
  • 4
  • 18
  • Maybe [this](https://stackoverflow.com/questions/45427735/android-studio-get-firebase-token-from-getidtoken/45427901) can help you. And the [official docs](https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseUser#getIdToken(boolean)) – Om Gupta Jan 09 '21 at 06:44
  • @OmGupta yes this is the way we can get token but how to send the updated token with every request ... m not sure – Nikhil Sharma Jan 09 '21 at 06:46
  • What do you mean by updated token? – Om Gupta Jan 09 '21 at 06:48
  • @OmGupta updated token means I need to send updated token with auth, as token will expired in 1 hour si if I cash it ho will I update it, I need to handle that and get new token/ or token which is not expired everytime – Nikhil Sharma Jan 09 '21 at 07:01
  • The link I sent above has the answer to your question. Passing forceRefresh as true will get you the updated token every time you call the getIdToken() method and will not give you the expired or invalid token. – Om Gupta Jan 09 '21 at 07:20
  • @OmGupta and what about getIdToken() returnig a task? Issue is not about getting updated token, issue is how will I make sure I am sending the non-expired token with every request, please help me with some code. – Nikhil Sharma Jan 09 '21 at 07:23

3 Answers3

2

You can get token from the returned task as below and can send it to header -

 task.getResult().getToken();
Priyanka
  • 1,791
  • 1
  • 7
  • 12
  • if I am getting a task them how will I make sure if I am sending the token not before competing task.. ? – Nikhil Sharma Jan 09 '21 at 07:46
  • 1
    You need to save the token value in the prefs and check if the value exists or not. If value exist then you can add to header if not then you can call the function that will provide the value first. – Priyanka Jan 09 '21 at 08:05
2

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 !!

Nikhil Sharma
  • 897
  • 1
  • 4
  • 18
2

Try this

FirebaseUserIdTokenInterceptor.java

public class FirebaseUserIdTokenInterceptor implements Interceptor {

    // Custom header for passing ID token in request.
    private static final String X_FIREBASE_ID_TOKEN = "YOUR-CUSTOM-HEADER";

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        try {
            FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
            if (user == null) return chain.proceed(request); // No has auth header

            Task<GetTokenResult> task = user.getIdToken(false);
            GetTokenResult tokenResult = Tasks.await(task, 10, TimeUnit.SECONDS); // Timeout 10 Seconds
            String idToken = tokenResult.getToken();
            if (idToken == null) return chain.proceed(request); // No has auth header

            return chain.proceed(request.newBuilder()
                    .addHeader(X_FIREBASE_ID_TOKEN, idToken)
                    .build()); // Has auth header
        } catch (Exception e) {
            return chain.proceed(request); // No has auth header
        }
    }
}

I found a way here and modified it for me.

GGalJJak
  • 111
  • 1
  • 3